/*      */ package com.zimbra.cs.mailbox;
/*      */ 
/*      */ import com.google.common.base.Joiner;
/*      */ import com.google.common.base.Objects;
/*      */ import com.google.common.base.Objects.ToStringHelper;
/*      */ import com.google.common.base.Splitter;
/*      */ import com.google.common.base.Strings;
/*      */ import com.google.common.collect.ImmutableList;
/*      */ import com.google.common.collect.ImmutableMap;
/*      */ import com.google.common.collect.ImmutableMap.Builder;
/*      */ import com.google.common.collect.ImmutableSet;
/*      */ import com.google.common.collect.Maps;
/*      */ import com.google.common.collect.Sets;
/*      */ import com.zimbra.common.mailbox.Color;
/*      */ import com.zimbra.common.mailbox.ContactConstants;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.util.ByteUtil;
/*      */ import com.zimbra.common.util.EmailUtil;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.Pair;
/*      */ import com.zimbra.common.util.StringUtil;
/*      */ import com.zimbra.common.util.SystemUtil;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.account.Account;
/*      */ import com.zimbra.cs.account.GuestAccount;
/*      */ import com.zimbra.cs.account.Server;
/*      */ import com.zimbra.cs.db.DbMailItem;
/*      */ import com.zimbra.cs.db.DbMailItem.LocationCount;
/*      */ import com.zimbra.cs.db.DbPendingAclPush;
/*      */ import com.zimbra.cs.db.DbTag;
/*      */ import com.zimbra.cs.index.IndexDocument;
/*      */ import com.zimbra.cs.index.SortBy;
/*      */ import com.zimbra.cs.index.SortBy.Direction;
/*      */ import com.zimbra.cs.mailbox.util.TypedIdList;
/*      */ import com.zimbra.cs.session.Session.Type;
/*      */ import com.zimbra.cs.store.MailboxBlob;
/*      */ import com.zimbra.cs.store.StagedBlob;
/*      */ import com.zimbra.cs.store.StoreManager;
/*      */ import com.zimbra.cs.util.Zimbra;
/*      */ import java.io.IOException;
/*      */ import java.io.InputStream;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Arrays;
/*      */ import java.util.Collection;
/*      */ import java.util.Collections;
/*      */ import java.util.Comparator;
/*      */ import java.util.EnumSet;
/*      */ import java.util.HashMap;
/*      */ import java.util.HashSet;
/*      */ import java.util.Iterator;
/*      */ import java.util.List;
/*      */ import java.util.Map;
/*      */ import java.util.Map.Entry;
/*      */ import java.util.Set;
/*      */ import java.util.TreeSet;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public abstract class MailItem
/*      */   implements Comparable<MailItem>, ScheduledTaskResult
/*      */ {
/*      */   public static final int FLAG_UNCHANGED = Integer.MIN_VALUE;
/*      */   public static final int MAX_FLAG_COUNT = 31;
/*      */   
/*      */   public static enum Type
/*      */   {
/*   78 */     UNKNOWN(-1), 
/*      */     
/*   80 */     FOLDER(1), 
/*      */     
/*   82 */     SEARCHFOLDER(2), 
/*      */     
/*   84 */     TAG(3), 
/*      */     
/*   86 */     CONVERSATION(4), 
/*      */     
/*   88 */     MESSAGE(5), 
/*      */     
/*   90 */     CONTACT(6), 
/*      */     
/*   92 */     INVITE(7), 
/*      */     
/*   94 */     DOCUMENT(8), 
/*      */     
/*   96 */     NOTE(9), 
/*      */     
/*   98 */     FLAG(10), 
/*      */     
/*  100 */     APPOINTMENT(11), 
/*      */     
/*  102 */     VIRTUAL_CONVERSATION(12), 
/*      */     
/*  104 */     MOUNTPOINT(13), 
/*      */     
/*  106 */     WIKI(14), 
/*      */     
/*  108 */     TASK(15), 
/*      */     
/*  110 */     CHAT(16), 
/*      */     
/*  112 */     COMMENT(17), 
/*      */     
/*  114 */     LINK(18);
/*      */     
/*      */     private static final Map<Byte, Type> BYTE2TYPE;
/*      */     
/*  118 */     static { ImmutableMap.Builder<Byte, Type> builder = ImmutableMap.builder();
/*  119 */       for (Type type : values()) {
/*  120 */         builder.put(Byte.valueOf(type.toByte()), type);
/*      */       }
/*  122 */       BYTE2TYPE = builder.build();
/*      */     }
/*      */     
/*      */ 
/*      */     private Type(int b)
/*      */     {
/*  128 */       this.btype = ((byte)b);
/*      */     }
/*      */     
/*      */     public byte toByte() {
/*  132 */       return this.btype;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     public String toString()
/*      */     {
/*  140 */       return name().toLowerCase();
/*      */     }
/*      */     
/*      */     public static String toString(Set<Type> types) {
/*  144 */       return Joiner.on(',').skipNulls().join(types);
/*      */     }
/*      */     
/*      */     public static Type of(byte b) {
/*  148 */       Type result = (Type)BYTE2TYPE.get(Byte.valueOf(b));
/*  149 */       return result != null ? result : UNKNOWN;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public static Type of(String name)
/*      */     {
/*  159 */       if (Strings.isNullOrEmpty(name)) {
/*  160 */         return UNKNOWN;
/*      */       }
/*      */       try {
/*  163 */         return valueOf(name.toUpperCase());
/*      */       } catch (IllegalArgumentException e) {
/*  165 */         if ("briefcase".equalsIgnoreCase(name))
/*  166 */           return DOCUMENT;
/*      */       }
/*  168 */       return UNKNOWN;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     private final byte btype;
/*      */     
/*      */ 
/*      */ 
/*      */     public static Set<Type> setOf(String csv)
/*      */     {
/*  181 */       Set<Type> result = EnumSet.noneOf(Type.class);
/*  182 */       for (String token : Splitter.on(',').trimResults().split(csv)) {
/*  183 */         Type type = of(token);
/*  184 */         if (type != UNKNOWN) {
/*  185 */           result.add(type);
/*      */         } else {
/*  187 */           throw new IllegalArgumentException(token);
/*      */         }
/*      */       }
/*  190 */       return result;
/*      */     }
/*      */     
/*      */     public boolean isLeafNode() {
/*  194 */       switch (MailItem.1.$SwitchMap$com$zimbra$cs$mailbox$MailItem$Type[ordinal()]) {
/*      */       case 1: 
/*      */       case 2: 
/*      */       case 3: 
/*      */       case 4: 
/*      */       case 5: 
/*      */       case 6: 
/*      */       case 7: 
/*      */       case 8: 
/*  203 */         return false;
/*      */       }
/*  205 */       return true;
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  213 */   public static final String[] TAG_UNCHANGED = null;
/*      */   
/*      */   public static final byte DEFAULT_COLOR = 0;
/*  216 */   public static final Color DEFAULT_COLOR_RGB = new Color((byte)0);
/*      */   protected int mId;
/*      */   protected UnderlyingData mData;
/*      */   
/*  220 */   public static enum IndexStatus { NO(-1), 
/*      */     
/*  222 */     DEFERRED(0), 
/*      */     
/*  224 */     STALE(1), 
/*      */     
/*  226 */     DONE(Integer.MAX_VALUE);
/*      */     
/*      */     private final int id;
/*      */     
/*      */     private IndexStatus(int id) {
/*  231 */       this.id = id;
/*      */     }
/*      */     
/*      */     public int id() {
/*  235 */       return this.id;
/*      */     }
/*      */     
/*      */     static IndexStatus of(int id) {
/*  239 */       switch (id) {
/*      */       case -1: 
/*  241 */         return NO;
/*      */       case 0: 
/*  243 */         return DEFERRED;
/*      */       case 1: 
/*  245 */         return STALE;
/*      */       }
/*  247 */       return DONE;
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class UnderlyingData implements Cloneable
/*      */   {
/*      */     public int id;
/*      */     public byte type;
/*  255 */     public int parentId = -1;
/*  256 */     public int folderId = -1;
/*      */     private String prevFolders;
/*  258 */     public int indexId = MailItem.IndexStatus.NO.id();
/*  259 */     public int imapId = -1;
/*      */     public String locator;
/*      */     private String blobDigest;
/*      */     public int date;
/*      */     public long size;
/*      */     public int unreadCount;
/*      */     private int flags;
/*  266 */     private String[] tags = NO_TAGS;
/*      */     private String subject;
/*      */     public String name;
/*      */     public String metadata;
/*      */     public int modMetadata;
/*      */     public int dateChanged;
/*      */     public int modContent;
/*      */     public String uuid;
/*      */     
/*      */     public String getSubject() {
/*  276 */       return this.subject;
/*      */     }
/*      */     
/*      */     public UnderlyingData setSubject(String value) {
/*  280 */       this.subject = DbMailItem.normalize(value, 1024);
/*  281 */       return this;
/*      */     }
/*      */     
/*      */     public String getPrevFolders() {
/*  285 */       return this.prevFolders;
/*      */     }
/*      */     
/*      */     public UnderlyingData setPrevFolders(String value) {
/*  289 */       this.prevFolders = value;
/*  290 */       return this;
/*      */     }
/*      */     
/*      */     public String getBlobDigest()
/*      */     {
/*  295 */       return this.blobDigest;
/*      */     }
/*      */     
/*      */     public UnderlyingData setBlobDigest(String digest) {
/*  299 */       this.blobDigest = ("".equals(digest) ? null : digest);
/*  300 */       return this;
/*      */     }
/*      */     
/*      */     public boolean isUnread() {
/*  304 */       return this.unreadCount > 0;
/*      */     }
/*      */     
/*      */     public int getFlags() {
/*  308 */       return this.flags;
/*      */     }
/*      */     
/*      */     public UnderlyingData setFlag(Flag flag) {
/*  312 */       return setFlags(this.flags | flag.toBitmask());
/*      */     }
/*      */     
/*      */     public UnderlyingData setFlag(Flag.FlagInfo flag) {
/*  316 */       return setFlags(this.flags | flag.toBitmask());
/*      */     }
/*      */     
/*      */     public UnderlyingData unsetFlag(Flag flag) {
/*  320 */       return setFlags(this.flags & (flag.toBitmask() ^ 0xFFFFFFFF));
/*      */     }
/*      */     
/*      */     public UnderlyingData unsetFlag(Flag.FlagInfo flag) {
/*  324 */       return setFlags(this.flags & (flag.toBitmask() ^ 0xFFFFFFFF));
/*      */     }
/*      */     
/*      */     public UnderlyingData setFlags(int bitfield)
/*      */     {
/*  329 */       assert ((bitfield & (Flag.FLAGS_ALL ^ 0xFFFFFFFF)) == 0) : ("Invalid flag bitfield: " + bitfield);
/*  330 */       this.flags = (bitfield & Flag.FLAGS_ALL);
/*  331 */       return this;
/*      */     }
/*      */     
/*      */     public boolean isSet(Flag.FlagInfo flag) {
/*  335 */       return (flag != null) && ((this.flags & flag.toBitmask()) != 0);
/*      */     }
/*      */     
/*  338 */     private static final String[] NO_TAGS = new String[0];
/*      */     private static final String FN_ID = "id";
/*      */     
/*  341 */     public UnderlyingData setTags(Tag.NormalizedTags ntags) { this.tags = (ntags == null ? NO_TAGS : ntags.getTags());
/*  342 */       return this;
/*      */     }
/*      */     
/*      */     public String[] getTags() {
/*  346 */       return this.tags;
/*      */     }
/*      */     
/*      */     UnderlyingData duplicate(int newId, String newUuid, int newFolder, String newLocator) {
/*  350 */       UnderlyingData data = new UnderlyingData();
/*  351 */       data.id = newId;
/*  352 */       data.uuid = newUuid;
/*  353 */       data.type = this.type;
/*  354 */       data.parentId = this.parentId;
/*  355 */       data.folderId = newFolder;
/*  356 */       data.indexId = this.indexId;
/*  357 */       data.imapId = (this.imapId <= 0 ? this.imapId : newId);
/*  358 */       data.locator = newLocator;
/*  359 */       data.blobDigest = this.blobDigest;
/*  360 */       data.date = this.date;
/*  361 */       data.size = this.size;
/*  362 */       data.flags = this.flags;
/*  363 */       data.tags = this.tags;
/*  364 */       data.subject = this.subject;
/*  365 */       data.name = this.name;
/*  366 */       data.unreadCount = this.unreadCount;
/*  367 */       return data;
/*      */     }
/*      */     
/*      */     protected UnderlyingData clone()
/*      */     {
/*      */       try {
/*  373 */         return (UnderlyingData)super.clone();
/*      */       } catch (CloneNotSupportedException cnse) {}
/*  375 */       return null;
/*      */     }
/*      */     
/*      */     private void metadataChanged(Mailbox mbox, boolean updateFolderMODSEQ) throws ServiceException
/*      */     {
/*  380 */       this.modMetadata = mbox.getOperationChangeID();
/*  381 */       this.dateChanged = mbox.getOperationTimestamp();
/*  382 */       if ((updateFolderMODSEQ) && (!MailItem.isAcceptableType(MailItem.Type.FOLDER, MailItem.Type.of(this.type))) && (!MailItem.isAcceptableType(MailItem.Type.TAG, MailItem.Type.of(this.type)))) {
/*  383 */         mbox.getFolderById(this.folderId).updateHighestMODSEQ();
/*      */       }
/*      */     }
/*      */     
/*      */     void contentChanged(Mailbox mbox, boolean updateFolderMODSEQ) throws ServiceException {
/*  388 */       metadataChanged(mbox, updateFolderMODSEQ);
/*  389 */       this.modContent = this.modMetadata;
/*      */     }
/*      */     
/*      */     void contentChanged(Mailbox mbox) throws ServiceException {
/*  393 */       contentChanged(mbox, true);
/*      */     }
/*      */     
/*      */ 
/*      */     private static final String FN_TYPE = "tp";
/*      */     private static final String FN_PARENT_ID = "pid";
/*      */     private static final String FN_FOLDER_ID = "fid";
/*      */     private static final String FN_PREV_FOLDER = "pfid";
/*      */     private static final String FN_INDEX_ID = "idx";
/*      */     private static final String FN_IMAP_ID = "imap";
/*      */     private static final String FN_LOCATOR = "loc";
/*      */     private static final String FN_BLOB_DIGEST = "dgst";
/*      */     private static final String FN_DATE = "dt";
/*      */     private static final String FN_SIZE = "sz";
/*      */     private static final String FN_UNREAD_COUNT = "uc";
/*      */     private static final String FN_FLAGS = "fg";
/*      */     private static final String FN_TAGS = "tg";
/*      */     private static final String FN_SUBJECT = "sbj";
/*      */     private static final String FN_NAME = "nm";
/*      */     private static final String FN_METADATA = "meta";
/*      */     private static final String FN_MOD_METADATA = "modm";
/*      */     private static final String FN_MOD_CONTENT = "modc";
/*      */     private static final String FN_DATE_CHANGED = "dc";
/*      */     Metadata serialize()
/*      */     {
/*  418 */       Metadata meta = new Metadata();
/*  419 */       meta.put("id", this.id);
/*  420 */       meta.put("tp", this.type);
/*  421 */       meta.put("pid", this.parentId);
/*  422 */       meta.put("fid", this.folderId);
/*  423 */       meta.put("pfid", this.prevFolders);
/*  424 */       meta.put("idx", this.indexId);
/*  425 */       meta.put("imap", this.imapId);
/*  426 */       meta.put("loc", this.locator);
/*  427 */       meta.put("dgst", this.blobDigest);
/*  428 */       meta.put("dt", this.date);
/*  429 */       meta.put("sz", this.size);
/*  430 */       meta.put("uc", this.unreadCount);
/*  431 */       meta.put("fg", this.flags);
/*  432 */       meta.put("tg", DbTag.serializeTags(this.tags));
/*  433 */       meta.put("sbj", this.subject);
/*  434 */       meta.put("nm", this.name);
/*  435 */       meta.put("meta", this.metadata);
/*  436 */       meta.put("modm", this.modMetadata);
/*  437 */       meta.put("modc", this.modContent);
/*  438 */       meta.put("dc", this.dateChanged);
/*  439 */       return meta;
/*      */     }
/*      */     
/*      */     public void deserialize(Metadata meta) throws ServiceException {
/*  443 */       this.id = ((int)meta.getLong("id", 0L));
/*  444 */       this.type = ((byte)(int)meta.getLong("tp", 0L));
/*  445 */       this.parentId = ((int)meta.getLong("pid", -1L));
/*  446 */       this.folderId = ((int)meta.getLong("fid", -1L));
/*  447 */       this.prevFolders = meta.get("pfid", null);
/*  448 */       this.indexId = meta.getInt("idx", MailItem.IndexStatus.NO.id());
/*  449 */       this.imapId = ((int)meta.getLong("imap", -1L));
/*  450 */       this.locator = meta.get("loc", null);
/*  451 */       this.blobDigest = meta.get("dgst", null);
/*  452 */       this.date = ((int)meta.getLong("dt", 0L));
/*  453 */       this.size = meta.getLong("sz", 0L);
/*  454 */       this.unreadCount = ((int)meta.getLong("uc", 0L));
/*  455 */       setFlags((int)meta.getLong("fg", 0L));
/*      */       
/*  457 */       setTags(new Tag.NormalizedTags(DbTag.deserializeTags(meta.get("tg", null))));
/*  458 */       this.subject = meta.get("sbj", null);
/*  459 */       this.name = meta.get("nm", null);
/*  460 */       this.metadata = meta.get("meta", null);
/*  461 */       this.modMetadata = ((int)meta.getLong("modm", 0L));
/*  462 */       this.modContent = ((int)meta.getLong("modc", 0L));
/*  463 */       this.dateChanged = ((int)meta.getLong("dc", 0L));
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/*  468 */       return Objects.toStringHelper(this).add("id", this.id).add("type", MailItem.Type.of(this.type)).toString();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   public static final class TargetConstraint
/*      */   {
/*      */     public static final short INCLUDE_TRASH = 1;
/*      */     
/*      */     public static final short INCLUDE_SPAM = 2;
/*      */     public static final short INCLUDE_SENT = 4;
/*      */     public static final short INCLUDE_DRAFTS = 8;
/*      */     public static final short INCLUDE_OTHERS = 32;
/*      */     public static final short INCLUDE_QUERY = 16;
/*      */     private static final short ALL_LOCATIONS = 47;
/*      */     private static final char ENC_TRASH = 't';
/*      */     private static final char ENC_SPAM = 'j';
/*      */     private static final char ENC_SENT = 's';
/*      */     private static final char ENC_OTHER = 'o';
/*      */     private static final char ENC_QUERY = 'q';
/*      */     private static final char ENC_DRAFTS = 'd';
/*      */     private short inclusions;
/*      */     private String query;
/*      */     private final Mailbox mailbox;
/*  492 */     private int sentFolder = -1;
/*      */     
/*      */     public TargetConstraint(Mailbox mbox, short include) {
/*  495 */       this(mbox, include, null);
/*      */     }
/*      */     
/*      */     public TargetConstraint(Mailbox mbox, String includeQuery) {
/*  499 */       this(mbox, (short)16, includeQuery);
/*      */     }
/*      */     
/*      */     public TargetConstraint(Mailbox mbox, short include, String includeQuery) {
/*  503 */       this.mailbox = mbox;
/*  504 */       if ((includeQuery == null) || (includeQuery.trim().length() == 0)) {
/*  505 */         this.inclusions = ((short)(include & 0xFFFFFFEF));
/*      */       } else {
/*  507 */         this.inclusions = ((short)(include | 0x10));
/*  508 */         this.query = includeQuery;
/*      */       }
/*      */     }
/*      */     
/*      */     public static TargetConstraint parseConstraint(Mailbox mbox, String encoded) throws ServiceException {
/*  513 */       if (encoded == null) {
/*  514 */         return null;
/*      */       }
/*      */       
/*  517 */       boolean invert = false;
/*  518 */       short inclusions = 0;
/*  519 */       String query = null;
/*  520 */       for (int i = 0; i < encoded.length(); i++) {
/*  521 */         switch (encoded.charAt(i)) {
/*  522 */         case 't':  inclusions = (short)(inclusions | 0x1); break;
/*  523 */         case 'j':  inclusions = (short)(inclusions | 0x2); break;
/*  524 */         case 's':  inclusions = (short)(inclusions | 0x4); break;
/*  525 */         case 'd':  inclusions = (short)(inclusions | 0x8); break;
/*  526 */         case 'o':  inclusions = (short)(inclusions | 0x20); break;
/*  527 */         case 'q':  inclusions = (short)(inclusions | 0x10);
/*  528 */           query = encoded.substring(i + 1); break;
/*  529 */         case '-':  if ((i == 0) && (encoded.length() > 1)) invert = true;
/*      */           break; }
/*  531 */         throw ServiceException.INVALID_REQUEST("invalid encoded constraint: " + encoded, null);
/*      */       }
/*      */       
/*  534 */       if (invert) {
/*  535 */         inclusions = (short)(inclusions ^ 0x2F);
/*      */       }
/*  537 */       return new TargetConstraint(mbox, inclusions, query);
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/*  542 */       if (this.inclusions == 0) {
/*  543 */         return "";
/*      */       }
/*      */       
/*  546 */       StringBuilder sb = new StringBuilder();
/*  547 */       if ((this.inclusions & 0x1) != 0) {
/*  548 */         sb.append('t');
/*      */       }
/*  550 */       if ((this.inclusions & 0x2) != 0) {
/*  551 */         sb.append('j');
/*      */       }
/*  553 */       if ((this.inclusions & 0x4) != 0) {
/*  554 */         sb.append('s');
/*      */       }
/*  556 */       if ((this.inclusions & 0x8) != 0) {
/*  557 */         sb.append('d');
/*      */       }
/*  559 */       if ((this.inclusions & 0x20) != 0) {
/*  560 */         sb.append('o');
/*      */       }
/*  562 */       if ((this.inclusions & 0x10) != 0) {
/*  563 */         sb.append('q').append(this.query);
/*      */       }
/*  565 */       return sb.toString();
/*      */     }
/*      */     
/*      */     public static boolean checkItem(TargetConstraint tcon, MailItem item) throws ServiceException {
/*  569 */       return tcon == null ? true : tcon.checkItem(item);
/*      */     }
/*      */     
/*      */     private boolean checkItem(MailItem item) throws ServiceException
/*      */     {
/*  574 */       if ((this.inclusions & 0x2F) == 0)
/*  575 */         return false;
/*  576 */       if (((this.inclusions & 0x1) != 0) && (item.inTrash()))
/*  577 */         return true;
/*  578 */       if (((this.inclusions & 0x2) != 0) && (item.inSpam()))
/*  579 */         return true;
/*  580 */       if (((this.inclusions & 0x4) != 0) && (inSent(item)))
/*  581 */         return true;
/*  582 */       if (((this.inclusions & 0x8) != 0) && (item.inDrafts()))
/*  583 */         return true;
/*  584 */       if (((this.inclusions & 0x20) != 0) && (!item.inTrash()) && (!item.inSpam()) && (!inSent(item)) && (!item.inDrafts()))
/*  585 */         return true;
/*  586 */       return false;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     private boolean inSent(MailItem item)
/*      */     {
/*  600 */       if (item.getFolderId() != 5) {
/*  601 */         return false;
/*      */       }
/*      */       
/*  604 */       if (this.sentFolder == -1) {
/*  605 */         this.sentFolder = 5;
/*      */         try {
/*  607 */           String sent = this.mailbox.getAccount().getAttr("zimbraPrefSentMailFolder", null);
/*  608 */           if (sent != null) {
/*  609 */             this.sentFolder = this.mailbox.getFolderByPath(null, sent).getId();
/*      */           }
/*      */         }
/*      */         catch (ServiceException e) {}
/*      */       }
/*      */       
/*  615 */       return (this.sentFolder == 5) && (this.sentFolder == item.getFolderId());
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class CustomMetadata extends HashMap<String, String>
/*      */   {
/*      */     private static final long serialVersionUID = -3866150929202858077L;
/*      */     private final String sectionKey;
/*      */     
/*      */     public CustomMetadata(String section)
/*      */     {
/*  626 */       super();
/*  627 */       this.sectionKey = section.trim();
/*      */     }
/*      */     
/*      */     public CustomMetadata(String section, String serialized) throws ServiceException {
/*  631 */       this(section);
/*      */       
/*  633 */       if (!StringUtil.isNullOrEmpty(serialized)) {
/*  634 */         for (Map.Entry<String, ?> entry : new Metadata(serialized).asMap().entrySet()) {
/*  635 */           put(entry.getKey(), entry.getValue().toString());
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */     public String getSectionKey() {
/*  641 */       return this.sectionKey;
/*      */     }
/*      */     
/*      */     public String getSerializedValue() {
/*  645 */       remove(null);
/*  646 */       return new Metadata(this).toString();
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/*  651 */       return this.sectionKey + ": " + super.toString();
/*      */     }
/*      */     
/*      */     public CustomMetadataList asList() {
/*  655 */       return isEmpty() ? null : new CustomMetadataList(this);
/*      */     }
/*      */     
/*      */     public static final class CustomMetadataList extends ArrayList<Pair<String, String>> {
/*      */       private static final long serialVersionUID = 3213399133413270157L;
/*      */       
/*      */       public CustomMetadataList() {
/*  662 */         super();
/*      */       }
/*      */       
/*      */       public CustomMetadataList(MailItem.CustomMetadata custom) {
/*  666 */         this();
/*  667 */         addSection(custom);
/*      */       }
/*      */       
/*      */       public void addSection(MailItem.CustomMetadata custom) {
/*  671 */         if (custom.isEmpty()) {
/*  672 */           removeSection(custom.getSectionKey());
/*      */         } else {
/*  674 */           addSection(custom.getSectionKey(), custom.getSerializedValue());
/*      */         }
/*      */       }
/*      */       
/*      */       public void addSection(String key, String encoded) {
/*  679 */         removeSection(key);
/*  680 */         if ((key != null) && (encoded != null)) {
/*  681 */           add(new Pair(key, encoded));
/*      */         }
/*      */       }
/*      */       
/*      */       public MailItem.CustomMetadata getSection(String key) throws ServiceException {
/*  686 */         if (!isEmpty()) {
/*  687 */           for (Pair<String, String> entry : this) {
/*  688 */             if (key.equals(entry.getFirst())) {
/*  689 */               return new MailItem.CustomMetadata((String)entry.getFirst(), (String)entry.getSecond());
/*      */             }
/*      */           }
/*      */         }
/*  693 */         return null;
/*      */       }
/*      */       
/*      */       public List<String> listSections() {
/*  697 */         List<String> sections = new ArrayList(size());
/*  698 */         for (Pair<String, String> entry : this) {
/*  699 */           sections.add(entry.getFirst());
/*      */         }
/*  701 */         return sections;
/*      */       }
/*      */       
/*      */       public void removeSection(String key) { Iterator<Pair<String, String>> it;
/*  705 */         if ((key != null) && (!isEmpty())) {
/*  706 */           for (it = iterator(); it.hasNext();) {
/*  707 */             if (key.equals(((Pair)it.next()).getFirst())) {
/*  708 */               it.remove();
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */       public long guessSize() {
/*  715 */         long size = 0L;
/*  716 */         if (!isEmpty()) {
/*  717 */           for (Pair<String, String> entry : this) {
/*  718 */             size += ((String)entry.getFirst()).length() + ((String)entry.getSecond()).length();
/*      */           }
/*      */         }
/*  721 */         return size;
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   protected Mailbox mMailbox;
/*      */   
/*      */   protected MailboxBlob mBlob;
/*  730 */   protected int mMetaVersion = 1;
/*  731 */   protected int mVersion = 1;
/*      */   protected List<MailItem> mRevisions;
/*      */   protected Color mRGBColor;
/*      */   protected MailItem.CustomMetadata.CustomMetadataList mExtendedData;
/*      */   protected ACL rights;
/*      */   private static final int TOTAL_METADATA_LIMIT = 10000;
/*      */   private static final String INVALID_NAME_CHARACTERS = "[:/\"\t\r\n]";
/*      */   private static final String INVALID_NAME_PATTERN = ".*[:/\"\t\r\n].*";
/*      */   
/*  740 */   MailItem(Mailbox mbox, UnderlyingData data) throws ServiceException { this(mbox, data, false); }
/*      */   
/*      */   MailItem(Mailbox mbox, UnderlyingData data, boolean skipCache) throws ServiceException
/*      */   {
/*  744 */     if (data == null) {
/*  745 */       throw new IllegalArgumentException();
/*      */     }
/*  747 */     this.mId = data.id;
/*  748 */     this.mData = data;
/*  749 */     this.mMailbox = mbox;
/*  750 */     decodeMetadata(this.mData.metadata);
/*  751 */     checkItemCreationAllowed();
/*  752 */     this.mData.metadata = null;
/*      */     
/*  754 */     if ((!skipCache) && ((data.getFlags() & Flag.BITMASK_UNCACHED) == 0)) {
/*  755 */       mbox.cache(this);
/*      */     }
/*      */   }
/*      */   
/*      */   protected void checkItemCreationAllowed() throws ServiceException
/*      */   {
/*  761 */     if (getAccount().isIsExternalVirtualAccount()) {
/*  762 */       throw ServiceException.PERM_DENIED("permission denied for external account");
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   public int getId()
/*      */   {
/*  769 */     return this.mData.id;
/*      */   }
/*      */   
/*      */   public String getUuid()
/*      */   {
/*  774 */     return this.mData.uuid;
/*      */   }
/*      */   
/*      */   public Type getType()
/*      */   {
/*  779 */     return Type.of(this.mData.type);
/*      */   }
/*      */   
/*      */   public int getMailboxId()
/*      */   {
/*  784 */     return this.mMailbox.getId();
/*      */   }
/*      */   
/*      */   public Mailbox getMailbox()
/*      */   {
/*  789 */     return this.mMailbox;
/*      */   }
/*      */   
/*      */   public Account getAccount() throws ServiceException
/*      */   {
/*  794 */     return this.mMailbox.getAccount();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public byte getColor()
/*      */   {
/*  801 */     return this.mRGBColor.getMappedColor();
/*      */   }
/*      */   
/*      */   public Color getRgbColor()
/*      */   {
/*  806 */     return this.mRGBColor;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public String getName()
/*      */   {
/*  814 */     return this.mData.name == null ? "" : StringUtil.trimTrailingSpaces(this.mData.name);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public int getParentId()
/*      */   {
/*  821 */     return this.mData.parentId;
/*      */   }
/*      */   
/*      */ 
/*      */   public int getFolderId()
/*      */   {
/*  827 */     return this.mData.folderId;
/*      */   }
/*      */   
/*      */ 
/*      */   public String getPrevFolders()
/*      */   {
/*  833 */     return this.mData.prevFolders;
/*      */   }
/*      */   
/*      */ 
/*      */   public int getPrevFolderAtModseq(int modseq)
/*      */   {
/*  839 */     if (StringUtil.isNullOrEmpty(this.mData.prevFolders)) {
/*  840 */       return -1;
/*      */     }
/*  842 */     String[] modseq2FolderId = this.mData.prevFolders.split(";");
/*  843 */     if (modseq2FolderId.length > 0) {
/*  844 */       int index = 0;
/*      */       try
/*      */       {
/*  847 */         while ((index < modseq2FolderId.length) && (index < getAccount().getServer().getPrevFoldersToTrackMax())) {
/*  848 */           String md2id = modseq2FolderId[(index++)];
/*  849 */           String[] pair = md2id.split(":");
/*  850 */           int md = Integer.parseInt(pair[0]);
/*  851 */           if (modseq < md) {
/*  852 */             return Integer.parseInt(pair[1]);
/*      */           }
/*      */         }
/*      */       } catch (Exception e) {}
/*      */     }
/*  857 */     return -1;
/*      */   }
/*      */   
/*      */   public String getFolderUuid() throws ServiceException {
/*  861 */     Folder f = getFolder();
/*  862 */     return f != null ? f.getUuid() : null;
/*      */   }
/*      */   
/*      */ 
/*      */   public String getPath()
/*      */     throws ServiceException
/*      */   {
/*  869 */     Folder folder = !inDumpster() ? getFolder() : getMailbox().getFolderById(3);
/*  870 */     if (folder == null) {
/*  871 */       return null;
/*      */     }
/*  873 */     String path = folder.getPath();String name = getName();
/*  874 */     if ((name == null) || (path == null))
/*  875 */       return null;
/*  876 */     return path + (path.endsWith("/") ? "" : "/") + name;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getIndexId()
/*      */   {
/*  884 */     return this.mData.indexId;
/*      */   }
/*      */   
/*      */   public IndexStatus getIndexStatus() {
/*  888 */     return IndexStatus.of(this.mData.indexId);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getImapUid()
/*      */   {
/*  896 */     return this.mData.imapId;
/*      */   }
/*      */   
/*      */ 
/*      */   public String getLocator()
/*      */   {
/*  902 */     return this.mData.locator;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public String getDigest()
/*      */   {
/*  909 */     return this.mData.getBlobDigest();
/*      */   }
/*      */   
/*      */ 
/*      */   public int getMetadataVersion()
/*      */   {
/*  915 */     return this.mMetaVersion;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public int getVersion()
/*      */   {
/*  922 */     return this.mVersion;
/*      */   }
/*      */   
/*      */ 
/*      */   public long getDate()
/*      */   {
/*  928 */     return this.mData.date * 1000L;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public int getSavedSequence()
/*      */   {
/*  935 */     return this.mData.modContent;
/*      */   }
/*      */   
/*      */ 
/*      */   public long getChangeDate()
/*      */   {
/*  941 */     return this.mData.dateChanged * 1000L;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public int getModifiedSequence()
/*      */   {
/*  948 */     return this.mData.modMetadata;
/*      */   }
/*      */   
/*      */ 
/*      */   public long getSize()
/*      */   {
/*  954 */     return this.mData.size;
/*      */   }
/*      */   
/*      */ 
/*      */   public long getTotalSize()
/*      */     throws ServiceException
/*      */   {
/*  961 */     long size = this.mData.size;
/*  962 */     if (isTagged(Flag.FlagInfo.VERSIONED)) {
/*  963 */       for (MailItem revision : loadRevisions()) {
/*  964 */         size += revision.getSize();
/*      */       }
/*      */     }
/*  967 */     return size;
/*      */   }
/*      */   
/*      */   public String getSubject() {
/*  971 */     return Strings.nullToEmpty(this.mData.getSubject());
/*      */   }
/*      */   
/*      */ 
/*      */   public UnderlyingData getUnderlyingData()
/*      */   {
/*  977 */     this.mData.metadata = encodeMetadata().toString();
/*  978 */     return this.mData;
/*      */   }
/*      */   
/*      */   public abstract String getSender();
/*      */   
/*      */   public String getSortSubject()
/*      */   {
/*  985 */     return getSubject();
/*      */   }
/*      */   
/*      */   public String getSortSender()
/*      */   {
/*  990 */     return getSender();
/*      */   }
/*      */   
/*      */   public String getSortRecipients()
/*      */   {
/*  995 */     return null;
/*      */   }
/*      */   
/*      */ 
/*      */   public int getFlagBitmask()
/*      */   {
/* 1001 */     int flags = this.mData.getFlags();
/* 1002 */     if (isUnread()) {
/* 1003 */       flags |= Flag.BITMASK_UNREAD;
/*      */     }
/* 1005 */     return flags;
/*      */   }
/*      */   
/*      */   public List<String> getCustomDataSections() {
/* 1009 */     if ((this.mExtendedData == null) || (this.mExtendedData.isEmpty())) {
/* 1010 */       return Collections.emptyList();
/*      */     }
/* 1012 */     return this.mExtendedData.listSections();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public CustomMetadata getCustomData(String section)
/*      */     throws ServiceException
/*      */   {
/* 1020 */     if ((section == null) || (this.mExtendedData == null)) {
/* 1021 */       return null;
/*      */     }
/* 1023 */     return this.mExtendedData.getSection(section);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void setCustomData(CustomMetadata custom)
/*      */     throws ServiceException
/*      */   {
/* 1033 */     if (custom == null) {
/* 1034 */       return;
/*      */     }
/* 1036 */     if (!canAccess((short)2)) {
/* 1037 */       throw ServiceException.PERM_DENIED("you do not have the necessary permissions on the item");
/*      */     }
/*      */     
/* 1040 */     markItemModified(524288);
/*      */     
/* 1042 */     if (this.mExtendedData != null) {
/* 1043 */       this.mExtendedData.addSection(custom);
/* 1044 */     } else if (!custom.isEmpty()) {
/* 1045 */       this.mExtendedData = custom.asList();
/*      */     }
/*      */     
/* 1048 */     if ((this.mExtendedData != null) && (!custom.isEmpty()) && (this.mExtendedData.guessSize() > 10000L)) {
/* 1049 */       throw MailServiceException.TOO_MUCH_METADATA(10000);
/*      */     }
/*      */     
/* 1052 */     saveMetadata();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getInternalFlagBitmask()
/*      */   {
/* 1061 */     return this.mData.getFlags() & (Flag.BITMASK_IN_DUMPSTER ^ 0xFFFFFFFF);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public String getFlagString()
/*      */   {
/* 1069 */     long flags = this.mData.getFlags();
/* 1070 */     if (flags == 0L) {
/* 1071 */       return isUnread() ? Flag.UNREAD_FLAG_ONLY : "";
/*      */     }
/* 1073 */     return Flag.toString((int)(flags | (isUnread() ? Flag.BITMASK_UNREAD : 0)));
/*      */   }
/*      */   
/*      */   public String[] getTags()
/*      */   {
/* 1078 */     String[] tags = this.mData.getTags();String[] copy = tags.length == 0 ? tags : new String[tags.length];
/* 1079 */     System.arraycopy(tags, 0, copy, 0, tags.length);
/* 1080 */     return copy;
/*      */   }
/*      */   
/*      */   public boolean isTagged(Flag.FlagInfo finfo) {
/* 1084 */     return this.mData.isSet(finfo);
/*      */   }
/*      */   
/*      */   public boolean isTagged(Tag tag) {
/* 1088 */     if ((tag instanceof Flag)) {
/* 1089 */       return (this.mData.getFlags() & ((Flag)tag).toBitmask()) != 0;
/*      */     }
/* 1091 */     return Arrays.asList(this.mData.getTags()).contains(tag.getName());
/*      */   }
/*      */   
/*      */   public boolean isTagged(String tagName)
/*      */   {
/* 1096 */     if (StringUtil.isNullOrEmpty(tagName))
/* 1097 */       return false;
/* 1098 */     if (tagName.startsWith("\\")) {
/* 1099 */       return this.mData.isSet(Flag.FlagInfo.of(tagName));
/*      */     }
/* 1101 */     return Arrays.asList(this.mData.getTags()).contains(tagName);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean isFlagSet(long mask)
/*      */   {
/* 1109 */     return (getFlagBitmask() & mask) != 0L;
/*      */   }
/*      */   
/*      */ 
/*      */   public boolean isUnread()
/*      */   {
/* 1115 */     return this.mData.unreadCount > 0;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getUnreadCount()
/*      */   {
/* 1124 */     return this.mData.unreadCount;
/*      */   }
/*      */   
/*      */   public boolean isFlagged() {
/* 1128 */     return isTagged(Flag.FlagInfo.FLAGGED);
/*      */   }
/*      */   
/*      */   public boolean hasAttachment() {
/* 1132 */     return isTagged(Flag.FlagInfo.ATTACHED);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean inMailbox()
/*      */     throws ServiceException
/*      */   {
/* 1143 */     return (!inSpam()) && (!inTrash());
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public boolean inTrash()
/*      */     throws ServiceException
/*      */   {
/* 1151 */     if (this.mData.folderId <= 18) {
/* 1152 */       return this.mData.folderId == 3;
/*      */     }
/* 1154 */     Folder folder = this.mMailbox.getFolderById(null, getFolderId());
/* 1155 */     return folder.inTrash();
/*      */   }
/*      */   
/*      */ 
/*      */   public boolean inSpam()
/*      */   {
/* 1161 */     return this.mData.folderId == 4;
/*      */   }
/*      */   
/*      */ 
/*      */   public boolean inDrafts()
/*      */   {
/* 1167 */     return this.mData.folderId == 6;
/*      */   }
/*      */   
/*      */   public boolean inDumpster() {
/* 1171 */     return (this.mData.getFlags() & Flag.BITMASK_IN_DUMPSTER) != 0;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean canAccess(short rightsNeeded)
/*      */     throws ServiceException
/*      */   {
/* 1190 */     return canAccess(rightsNeeded, this.mMailbox.getAuthenticatedAccount(), this.mMailbox.isUsingAdminPrivileges());
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean canAccess(short rightsNeeded, Account authuser, boolean asAdmin)
/*      */     throws ServiceException
/*      */   {
/* 1208 */     if (rightsNeeded == 0) {
/* 1209 */       return true;
/*      */     }
/* 1211 */     return checkRights(rightsNeeded, authuser, asAdmin) == rightsNeeded;
/*      */   }
/*      */   
/*      */   private boolean isAllowedExternalDomain(String extUserEmail) throws ServiceException {
/* 1215 */     if (!getAccount().isExternalShareDomainWhitelistEnabled()) {
/* 1216 */       return true;
/*      */     }
/* 1218 */     if (extUserEmail == null) {
/* 1219 */       return false;
/*      */     }
/* 1221 */     String[] localPartAndDomain = EmailUtil.getLocalPartAndDomain(extUserEmail);
/* 1222 */     if (localPartAndDomain == null) {
/* 1223 */       return false;
/*      */     }
/* 1225 */     String extUserDomain = localPartAndDomain[1];
/* 1226 */     String[] whitelistDomains = getAccount().getExternalShareWhitelistDomain();
/* 1227 */     for (String domain : whitelistDomains) {
/* 1228 */       if (domain.equalsIgnoreCase(extUserDomain)) {
/* 1229 */         return true;
/*      */       }
/*      */     }
/* 1232 */     return false;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   short checkRights(short rightsNeeded, Account authuser, boolean asAdmin)
/*      */     throws ServiceException
/*      */   {
/* 1249 */     if (hasFullPermission(authuser)) {
/* 1250 */       return rightsNeeded;
/*      */     }
/* 1252 */     if ((GuestAccount.ANONYMOUS_ACCT.equals(authuser)) && (!getAccount().isPublicSharingEnabled())) {
/* 1253 */       return 0;
/*      */     }
/*      */     
/* 1256 */     if ((authuser.isIsExternalVirtualAccount()) && ((!getAccount().isExternalSharingEnabled()) || (!isAllowedExternalDomain(authuser.getExternalUserMailAddress()))))
/*      */     {
/*      */ 
/* 1259 */       return 0;
/*      */     }
/*      */     
/* 1262 */     Folder folder = !inDumpster() ? getFolder() : getMailbox().getFolderById(3);
/* 1263 */     short granted = 0;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 1268 */     if ((isLeafNode()) && (isTagged(Flag.FlagInfo.NO_INHERIT))) {
/* 1269 */       granted = (short)(checkACL(rightsNeeded, authuser, asAdmin) | folder.checkRights(rightsNeeded, authuser, asAdmin));
/* 1270 */     } else if (isTagged(Flag.FlagInfo.NO_INHERIT)) {
/* 1271 */       granted = checkACL(rightsNeeded, authuser, asAdmin);
/*      */     } else {
/* 1273 */       granted = folder.checkRights(rightsNeeded, authuser, asAdmin);
/*      */     }
/* 1275 */     short subset = (short)(granted & rightsNeeded);
/*      */     
/*      */ 
/*      */ 
/* 1279 */     if (ZimbraLog.acl.isTraceEnabled()) {
/* 1280 */       ZimbraLog.acl.trace("checkRights '%s' returned=%s granted=%s needed=%s", new Object[] { getPath(), Short.valueOf(subset), Short.valueOf(granted), Short.valueOf(rightsNeeded) });
/*      */     }
/*      */     
/* 1283 */     return subset;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected boolean hasFullPermission(Account authuser)
/*      */   {
/* 1294 */     if ((authuser == null) || (authuser.getId().equals(this.mMailbox.getAccountId())))
/* 1295 */       return true;
/* 1296 */     return false;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public synchronized MailboxBlob getBlob()
/*      */     throws ServiceException
/*      */   {
/* 1307 */     if ((this.mBlob == null) && (getDigest() != null)) {
/* 1308 */       this.mBlob = StoreManager.getInstance().getMailboxBlob(this);
/* 1309 */       if (this.mBlob == null) {
/* 1310 */         throw MailServiceException.NO_SUCH_BLOB(this.mMailbox.getId(), this.mId, this.mData.modContent);
/*      */       }
/*      */     }
/* 1313 */     return this.mBlob;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public InputStream getContentStream()
/*      */     throws ServiceException
/*      */   {
/* 1326 */     if (getDigest() == null) {
/* 1327 */       return null;
/*      */     }
/*      */     try
/*      */     {
/* 1331 */       MailboxBlob mblob = getBlob();
/* 1332 */       if (mblob == null) {
/* 1333 */         throw ServiceException.FAILURE("missing blob for id: " + getId() + ", change: " + getModifiedSequence(), null);
/*      */       }
/* 1335 */       return StoreManager.getInstance().getContent(mblob);
/*      */     } catch (IOException e) {
/* 1337 */       String msg = String.format("Unable to get content for %s %d", new Object[] { getClass().getSimpleName(), Integer.valueOf(getId()) });
/* 1338 */       throw ServiceException.FAILURE(msg, e);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public byte[] getContent()
/*      */     throws ServiceException
/*      */   {
/* 1352 */     if (getDigest() == null) {
/* 1353 */       return null;
/*      */     }
/*      */     try
/*      */     {
/* 1357 */       return ByteUtil.getContent(getContentStream(), (int)getSize());
/*      */     } catch (IOException e) {
/* 1359 */       throw ServiceException.FAILURE("Unable to get content for item " + getId(), e);
/*      */     }
/*      */   }
/*      */   
/*      */   public int compareTo(MailItem that) {
/* 1364 */     if (this == that) {
/* 1365 */       return 0;
/*      */     }
/* 1367 */     return this.mId - that.getId();
/*      */   }
/*      */   
/*      */   public static final class SortIdAscending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1372 */       return m1.getId() - m2.getId();
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortIdDescending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1378 */       return m2.getId() - m1.getId();
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortModifiedSequenceAscending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1384 */       return m1.getModifiedSequence() - m2.getModifiedSequence();
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortDateAscending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1390 */       long t1 = m1.getDate();long t2 = m2.getDate();
/*      */       
/* 1392 */       if (t1 < t2) return -1;
/* 1393 */       if (t1 == t2) return 0;
/* 1394 */       return 1;
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortDateDescending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1400 */       long t1 = m1.getDate();long t2 = m2.getDate();
/*      */       
/* 1402 */       if (t1 < t2) return 1;
/* 1403 */       if (t1 == t2) return 0;
/* 1404 */       return -1;
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortSizeAscending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1410 */       long t1 = m1.getSize();long t2 = m2.getSize();
/*      */       
/* 1412 */       if (t1 < t2) return -1;
/* 1413 */       if (t1 == t2) return 0;
/* 1414 */       return 1;
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortSizeDescending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1420 */       long t1 = m1.getSize();long t2 = m2.getSize();
/*      */       
/* 1422 */       if (t1 < t2) return 1;
/* 1423 */       if (t1 == t2) return 0;
/* 1424 */       return -1;
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortImapUid implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1430 */       return m1.getImapUid() - m2.getImapUid();
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortSubjectAscending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1436 */       return m1.getSubject().compareToIgnoreCase(m2.getSubject());
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortSubjectDescending implements Comparator<MailItem> {
/*      */     public int compare(MailItem m1, MailItem m2) {
/* 1442 */       return -m1.getSubject().compareToIgnoreCase(m2.getSubject());
/*      */     }
/*      */   }
/*      */   
/*      */   public static abstract class SortNameNaturalOrder implements Comparator<MailItem> {
/*      */     private static class Name {
/*      */       public char[] buf;
/*      */       public int pos;
/*      */       public int len;
/*      */       
/*      */       public Name(String n) {
/* 1453 */         this.buf = n.toCharArray();
/* 1454 */         this.pos = 0;
/* 1455 */         this.len = this.buf.length;
/*      */       }
/*      */       
/*      */       public char getChar() {
/* 1459 */         if (this.pos < this.len)
/* 1460 */           return this.buf[this.pos];
/* 1461 */         return '\000';
/*      */       }
/*      */       
/*      */       public Name next() {
/* 1465 */         if (this.pos < this.len)
/* 1466 */           this.pos += 1;
/* 1467 */         return this;
/*      */       }
/*      */     }
/*      */     
/*      */     public int compare(MailItem m1, MailItem m2)
/*      */     {
/* 1473 */       if (m1.getName() == null)
/* 1474 */         return returnResult(1);
/* 1475 */       if (m2.getName() == null) {
/* 1476 */         return returnResult(-1);
/*      */       }
/* 1478 */       return compareString(new Name(m1.getName()), new Name(m2.getName()));
/*      */     }
/*      */     
/*      */     public int compareString(Name n1, Name n2) {
/* 1482 */       char first = n1.getChar();
/* 1483 */       char second = n2.getChar();
/*      */       
/* 1485 */       if ((isDigit(first)) && (isDigit(second)))
/* 1486 */         return compareNumeric(n1, n2);
/* 1487 */       if (first != second)
/* 1488 */         return returnResult(first - second);
/* 1489 */       if ((first == 0) && (second == 0)) {
/* 1490 */         return 0;
/*      */       }
/*      */       
/* 1493 */       return compareString(n1.next(), n2.next());
/*      */     }
/*      */     
/*      */     public int compareNumeric(Name n1, Name n2) {
/* 1497 */       int firstNum = readInt(n1);
/* 1498 */       int secondNum = readInt(n2);
/*      */       
/* 1500 */       if (firstNum != secondNum) {
/* 1501 */         return returnResult(firstNum - secondNum);
/*      */       }
/*      */       
/* 1504 */       return compareString(n1.next(), n2.next());
/*      */     }
/*      */     
/*      */     public int readInt(Name n) {
/* 1508 */       int start = n.pos;
/* 1509 */       int end = 0;
/* 1510 */       while (isDigit(n.getChar())) {
/* 1511 */         n.next();
/*      */       }
/* 1513 */       end = n.pos;
/* 1514 */       if (end == start) {
/* 1515 */         return 0;
/*      */       }
/*      */       try {
/* 1518 */         return Integer.parseInt(new String(n.buf, start, end - start));
/*      */       } catch (NumberFormatException e) {}
/* 1520 */       return 0;
/*      */     }
/*      */     
/*      */     public boolean isDigit(char c)
/*      */     {
/* 1525 */       return Character.isDigit(c);
/*      */     }
/*      */     
/*      */     protected abstract int returnResult(int paramInt);
/*      */   }
/*      */   
/*      */   public static final class SortNameNaturalOrderAscending extends MailItem.SortNameNaturalOrder {
/*      */     protected int returnResult(int result) {
/* 1533 */       return result;
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SortNameNaturalOrderDescending extends MailItem.SortNameNaturalOrder {
/*      */     protected int returnResult(int result) {
/* 1539 */       return -result;
/*      */     }
/*      */   }
/*      */   
/*      */   static Comparator<MailItem> getComparator(SortBy sort) {
/* 1544 */     boolean asc = sort.getDirection() == SortBy.Direction.ASC;
/* 1545 */     switch (sort.getKey()) {
/*      */     case ID: 
/* 1547 */       return asc ? new SortIdAscending() : new SortIdDescending();
/*      */     case DATE: 
/* 1549 */       return asc ? new SortDateAscending() : new SortDateDescending();
/*      */     case SIZE: 
/* 1551 */       return asc ? new SortSizeAscending() : new SortSizeDescending();
/*      */     case SUBJECT: 
/* 1553 */       return asc ? new SortSubjectAscending() : new SortSubjectDescending();
/*      */     case NAME_NATURAL_ORDER: 
/* 1555 */       return asc ? new SortNameNaturalOrderAscending() : new SortNameNaturalOrderDescending();
/*      */     }
/* 1557 */     return null;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public List<IndexDocument> generateIndexData()
/*      */     throws MailItem.TemporaryIndexingException
/*      */   {
/* 1579 */     return null;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   MailItem getParent()
/*      */     throws ServiceException
/*      */   {
/* 1589 */     if ((this.mData.parentId == -1) || (inDumpster()))
/* 1590 */       return null;
/* 1591 */     return this.mMailbox.getItemById(this.mData.parentId, Type.UNKNOWN);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1600 */   Folder getFolder()
/* 1600 */     throws ServiceException { return !inDumpster() ? this.mMailbox.getFolderById(this.mData.folderId) : null; }
/*      */   
/*      */   abstract boolean isTaggable();
/*      */   
/*      */   abstract boolean isCopyable();
/*      */   abstract boolean isMovable();
/*      */   abstract boolean isMutable();
/*      */   abstract boolean canHaveChildren();
/* 1608 */   boolean isDeletable() { return true; }
/* 1609 */   boolean isLeafNode() { return true; }
/* 1610 */   boolean trackUnread() { return true; }
/* 1611 */   boolean canParent(MailItem child) { return canHaveChildren(); }
/*      */   
/*      */   static MailItem getById(Mailbox mbox, int id) throws ServiceException
/*      */   {
/* 1615 */     return getById(mbox, id, Type.UNKNOWN);
/*      */   }
/*      */   
/*      */   static MailItem getById(Mailbox mbox, int id, Type type) throws ServiceException {
/* 1619 */     return getById(mbox, id, type, false);
/*      */   }
/*      */   
/*      */   static MailItem getById(Mailbox mbox, int id, Type type, boolean fromDumpster) throws ServiceException {
/* 1623 */     return mbox.getItem(DbMailItem.getById(mbox, id, type, fromDumpster));
/*      */   }
/*      */   
/*      */   static MailItem getByUuid(Mailbox mbox, String uuid, Type type) throws ServiceException {
/* 1627 */     return getByUuid(mbox, uuid, type, false);
/*      */   }
/*      */   
/*      */   static MailItem getByUuid(Mailbox mbox, String uuid, Type type, boolean fromDumpster) throws ServiceException {
/* 1631 */     return mbox.getItem(DbMailItem.getByUuid(mbox, uuid, type, fromDumpster));
/*      */   }
/*      */   
/*      */   static List<MailItem> getById(Mailbox mbox, Collection<Integer> ids, Type type) throws ServiceException {
/* 1635 */     if ((ids == null) || (ids.isEmpty())) {
/* 1636 */       return Collections.emptyList();
/*      */     }
/* 1638 */     List<MailItem> items = new ArrayList();
/* 1639 */     for (UnderlyingData ud : DbMailItem.getById(mbox, ids, type)) {
/* 1640 */       items.add(mbox.getItem(ud));
/*      */     }
/* 1642 */     return items;
/*      */   }
/*      */   
/*      */   static MailItem getByImapId(Mailbox mbox, int id, int folderId) throws ServiceException {
/* 1646 */     return mbox.getItem(DbMailItem.getByImapId(mbox, id, folderId));
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static MailItem constructItem(Mailbox mbox, UnderlyingData data, boolean skipCache)
/*      */     throws ServiceException
/*      */   {
/* 1657 */     if (data == null) {
/* 1658 */       throw noSuchItem(-1, Type.UNKNOWN);
/*      */     }
/* 1660 */     switch (Type.of(data.type)) {
/* 1661 */     case FOLDER:  return new Folder(mbox, data, skipCache);
/* 1662 */     case SEARCHFOLDER:  return new SearchFolder(mbox, data, skipCache);
/* 1663 */     case TAG:  return new Tag(mbox, data, skipCache);
/* 1664 */     case CONVERSATION:  return new Conversation(mbox, data, skipCache);
/* 1665 */     case MESSAGE:  return new Message(mbox, data, skipCache);
/* 1666 */     case CONTACT:  return new Contact(mbox, data, skipCache);
/* 1667 */     case DOCUMENT:  return new Document(mbox, data, skipCache);
/* 1668 */     case NOTE:  return new Note(mbox, data, skipCache);
/* 1669 */     case APPOINTMENT:  return new Appointment(mbox, data, skipCache);
/* 1670 */     case TASK:  return new Task(mbox, data, skipCache);
/* 1671 */     case MOUNTPOINT:  return new Mountpoint(mbox, data, skipCache);
/* 1672 */     case WIKI:  return new WikiItem(mbox, data, skipCache);
/* 1673 */     case CHAT:  return new Chat(mbox, data, skipCache);
/* 1674 */     case COMMENT:  return new Comment(mbox, data, skipCache);
/* 1675 */     case VIRTUAL_CONVERSATION:  return new VirtualConversation(mbox, data, skipCache); }
/* 1676 */     return null;
/*      */   }
/*      */   
/*      */   public static MailItem constructItem(Mailbox mbox, UnderlyingData data) throws ServiceException
/*      */   {
/* 1681 */     return constructItem(mbox, data, false);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static MailServiceException noSuchItem(int id, Type type)
/*      */   {
/* 1691 */     switch (type) {
/*      */     case FOLDER: 
/*      */     case SEARCHFOLDER: 
/*      */     case MOUNTPOINT: 
/* 1695 */       return MailServiceException.NO_SUCH_FOLDER(id);
/*      */     case FLAG: 
/*      */     case TAG: 
/* 1698 */       return MailServiceException.NO_SUCH_TAG(id);
/*      */     case CONVERSATION: 
/*      */     case VIRTUAL_CONVERSATION: 
/* 1701 */       return MailServiceException.NO_SUCH_CONV(id);
/*      */     case MESSAGE: 
/*      */     case CHAT: 
/* 1704 */       return MailServiceException.NO_SUCH_MSG(id);
/*      */     case CONTACT: 
/* 1706 */       return MailServiceException.NO_SUCH_CONTACT(id);
/*      */     case DOCUMENT: 
/*      */     case WIKI: 
/* 1709 */       return MailServiceException.NO_SUCH_DOC(id);
/*      */     case NOTE: 
/* 1711 */       return MailServiceException.NO_SUCH_NOTE(id);
/*      */     case APPOINTMENT: 
/* 1713 */       return MailServiceException.NO_SUCH_APPT(id);
/*      */     case TASK: 
/* 1715 */       return MailServiceException.NO_SUCH_TASK(id);
/*      */     }
/* 1717 */     return MailServiceException.NO_SUCH_ITEM(id);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static MailServiceException noSuchItemUuid(String uuid, Type type)
/*      */   {
/* 1729 */     switch (type) {
/*      */     case FOLDER: 
/*      */     case SEARCHFOLDER: 
/*      */     case MOUNTPOINT: 
/* 1733 */       return MailServiceException.NO_SUCH_FOLDER_UUID(uuid);
/*      */     case DOCUMENT: 
/*      */     case WIKI: 
/* 1736 */       return MailServiceException.NO_SUCH_DOC_UUID(uuid);
/*      */     }
/* 1738 */     return MailServiceException.NO_SUCH_ITEM_UUID(uuid);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static boolean isAcceptableType(Type desired, Type actual)
/*      */   {
/* 1755 */     if ((desired == actual) || (desired == Type.UNKNOWN)) {
/* 1756 */       return true;
/*      */     }
/*      */     
/* 1759 */     if ((desired == Type.FOLDER) && (actual == Type.SEARCHFOLDER))
/* 1760 */       return true;
/* 1761 */     if ((desired == Type.FOLDER) && (actual == Type.MOUNTPOINT))
/* 1762 */       return true;
/* 1763 */     if ((desired == Type.TAG) && (actual == Type.FLAG))
/* 1764 */       return true;
/* 1765 */     if ((desired == Type.CONVERSATION) && (actual == Type.VIRTUAL_CONVERSATION))
/* 1766 */       return true;
/* 1767 */     if ((desired == Type.DOCUMENT) && (actual == Type.WIKI))
/* 1768 */       return true;
/* 1769 */     if ((desired == Type.MESSAGE) && (actual == Type.CHAT)) {
/* 1770 */       return true;
/*      */     }
/*      */     
/* 1773 */     return false;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean isAcceptableType(Type desired)
/*      */   {
/* 1787 */     return isAcceptableType(desired, getType());
/*      */   }
/*      */   
/*      */   boolean checkChangeID() throws ServiceException {
/* 1791 */     return this.mMailbox.checkItemChangeID(this);
/*      */   }
/*      */   
/*      */ 
/*      */   void markItemCreated()
/*      */   {
/* 1797 */     this.mMailbox.markItemCreated(this);
/*      */   }
/*      */   
/*      */ 
/*      */   void markItemDeleted()
/*      */   {
/* 1803 */     this.mMailbox.markItemDeleted(this);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   void markItemModified(int reason)
/*      */     throws ServiceException
/*      */   {
/* 1812 */     this.mMailbox.markItemModified(this, reason);
/*      */   }
/*      */   
/*      */   void markBlobForDeletion()
/*      */   {
/*      */     try
/*      */     {
/* 1819 */       markBlobForDeletion(getBlob());
/*      */     } catch (ServiceException e) {
/* 1821 */       ZimbraLog.mailbox.warn("error queuing blob for deletion for id: " + this.mId + ", change: " + this.mData.modContent, e);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   void markBlobForDeletion(MailboxBlob mblob)
/*      */   {
/* 1829 */     if (mblob == null)
/* 1830 */       return;
/* 1831 */     PendingDelete info = new PendingDelete();
/* 1832 */     info.blobs.add(mblob);
/* 1833 */     this.mMailbox.markOtherItemDirty(info);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected void finishCreation(MailItem parent)
/*      */     throws ServiceException
/*      */   {
/* 1843 */     markItemCreated();
/*      */     
/*      */ 
/* 1846 */     if (parent != null) {
/* 1847 */       parent.addChild(this);
/*      */     }
/*      */     
/*      */ 
/* 1851 */     Folder folder = getFolder();
/* 1852 */     if (!folder.canContain(this)) {
/* 1853 */       throw MailServiceException.CANNOT_CONTAIN();
/*      */     }
/*      */     
/*      */ 
/* 1857 */     if (isLeafNode()) {
/* 1858 */       boolean isDeleted = isTagged(Flag.FlagInfo.DELETED);
/*      */       
/* 1860 */       this.mMailbox.updateSize(this.mData.size, isQuotaCheckRequired());
/* 1861 */       folder.updateSize(1, isDeleted ? 1 : 0, this.mData.size);
/* 1862 */       updateTagSizes(1, isDeleted ? 1 : 0, this.mData.size);
/*      */       
/*      */ 
/* 1865 */       folder.updateUnread(this.mData.unreadCount, isDeleted ? this.mData.unreadCount : 0);
/* 1866 */       updateTagUnread(this.mData.unreadCount, isDeleted ? this.mData.unreadCount : 0);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   protected boolean isQuotaCheckRequired()
/*      */     throws ServiceException
/*      */   {
/* 1876 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void setColor(Color color)
/*      */     throws ServiceException
/*      */   {
/* 1889 */     if (!canAccess((short)2))
/* 1890 */       throw ServiceException.PERM_DENIED("you do not have the necessary permissions on the item");
/* 1891 */     if (color.equals(this.mRGBColor)) {
/* 1892 */       return;
/*      */     }
/* 1894 */     markItemModified(8192);
/* 1895 */     this.mRGBColor.set(color);
/* 1896 */     saveMetadata();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   @Deprecated
/*      */   void setColor(byte color)
/*      */     throws ServiceException
/*      */   {
/* 1910 */     if (!canAccess((short)2)) {
/* 1911 */       throw ServiceException.PERM_DENIED("you do not have the necessary permissions on the item");
/*      */     }
/*      */     
/* 1914 */     if (color == this.mRGBColor.getMappedColor()) {
/* 1915 */       return;
/*      */     }
/* 1917 */     markItemModified(8192);
/* 1918 */     this.mRGBColor.setColor(color);
/* 1919 */     saveMetadata();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void setDate(long date)
/*      */     throws ServiceException
/*      */   {
/* 1930 */     if (this.mData.date == (int)(date / 1000L)) {
/* 1931 */       return;
/*      */     }
/*      */     
/* 1934 */     if (!canAccess((short)2)) {
/* 1935 */       throw ServiceException.PERM_DENIED("you do not have the necessary permissions on the item");
/*      */     }
/*      */     
/* 1938 */     if (ZimbraLog.mailop.isDebugEnabled()) {
/* 1939 */       ZimbraLog.mailop.debug("Setting date of %s to %d.", new Object[] { getMailopContext(this), Long.valueOf(date) });
/*      */     }
/* 1941 */     markItemModified(32);
/* 1942 */     this.mData.date = ((int)(date / 1000L));
/* 1943 */     metadataChanged();
/* 1944 */     DbMailItem.saveDate(this);
/*      */   }
/*      */   
/*      */ 
/*      */   void setImapUid(int imapId)
/*      */     throws ServiceException
/*      */   {
/* 1951 */     if (this.mData.imapId == imapId) {
/* 1952 */       return;
/*      */     }
/* 1954 */     if (ZimbraLog.mailop.isDebugEnabled()) {
/* 1955 */       ZimbraLog.mailop.debug("Setting imapId of %s to %d.", new Object[] { getMailopContext(this), Integer.valueOf(imapId) });
/*      */     }
/* 1957 */     markItemModified(128);
/* 1958 */     this.mData.imapId = imapId;
/* 1959 */     metadataChanged();
/* 1960 */     DbMailItem.saveImapUid(this);
/*      */     
/* 1962 */     getFolder().updateUIDNEXT();
/*      */   }
/*      */   
/*      */   MailboxBlob setContent(StagedBlob staged, Object content) throws ServiceException, IOException {
/* 1966 */     addRevision(false);
/*      */     
/*      */ 
/* 1969 */     markItemModified(65712);
/*      */     
/*      */ 
/* 1972 */     if (getSavedSequence() != this.mMailbox.getOperationChangeID()) {
/* 1973 */       if (!canAccess((short)2)) {
/* 1974 */         throw ServiceException.PERM_DENIED("you do not have the necessary permissions on the item");
/*      */       }
/* 1976 */       boolean delete = true;
/*      */       
/* 1978 */       if (isTagged(Flag.FlagInfo.VERSIONED)) {
/* 1979 */         List<MailItem> revisions = loadRevisions();
/* 1980 */         if (!revisions.isEmpty()) {
/* 1981 */           MailItem lastRev = (MailItem)revisions.get(revisions.size() - 1);
/* 1982 */           if (lastRev.getSavedSequence() == getSavedSequence()) {
/* 1983 */             delete = false;
/*      */           }
/*      */         }
/*      */       }
/* 1987 */       if (delete) {
/* 1988 */         markBlobForDeletion();
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 1993 */     MessageCache.purge(this);
/*      */     
/*      */ 
/* 1996 */     long size = staged == null ? 0L : staged.getSize();
/* 1997 */     if (this.mData.size != size) {
/* 1998 */       this.mMailbox.updateSize(size - this.mData.size, isQuotaCheckRequired());
/* 1999 */       this.mData.size = size;
/*      */     }
/* 2001 */     getFolder().updateSize(0, 0, size - this.mData.size);
/*      */     
/* 2003 */     this.mData.setBlobDigest(staged == null ? null : staged.getDigest());
/* 2004 */     this.mData.date = this.mMailbox.getOperationTimestamp();
/* 2005 */     this.mData.imapId = (this.mMailbox.isTrackingImap() ? 0 : this.mData.id);
/* 2006 */     contentChanged();
/*      */     
/*      */ 
/* 2009 */     MailboxBlob mblob = null;
/* 2010 */     if (staged != null) {
/* 2011 */       StoreManager sm = StoreManager.getInstance();
/*      */       
/* 2013 */       if (SystemUtil.ON_WINDOWS) {
/* 2014 */         mblob = sm.link(staged, this.mMailbox, this.mId, getSavedSequence());
/*      */       } else
/* 2016 */         mblob = sm.renameTo(staged, this.mMailbox, this.mId, getSavedSequence());
/* 2017 */       this.mMailbox.markOtherItemDirty(mblob);
/*      */     }
/* 2019 */     this.mBlob = null;
/* 2020 */     this.mData.locator = (mblob == null ? null : mblob.getLocator());
/*      */     
/*      */ 
/* 2023 */     reanalyze(content, size);
/*      */     
/* 2025 */     return mblob;
/*      */   }
/*      */   
/*      */   int getMaxRevisions() throws ServiceException
/*      */   {
/* 2030 */     return 1;
/*      */   }
/*      */   
/*      */   List<MailItem> loadRevisions() throws ServiceException {
/* 2034 */     if (this.mRevisions == null) {
/* 2035 */       this.mRevisions = new ArrayList();
/*      */       
/* 2037 */       if (isTagged(Flag.FlagInfo.VERSIONED)) {
/* 2038 */         for (UnderlyingData data : DbMailItem.getRevisionInfo(this, inDumpster())) {
/* 2039 */           this.mRevisions.add(constructItem(this.mMailbox, data));
/*      */         }
/*      */       }
/*      */     }
/* 2043 */     return this.mRevisions;
/*      */   }
/*      */   
/*      */   void addRevision(boolean persist) throws ServiceException {
/* 2047 */     addRevision(persist, true);
/*      */   }
/*      */   
/*      */   void addRevision(boolean persist, boolean updateFolderMODSEQ) throws ServiceException
/*      */   {
/* 2052 */     if (this.mData.modMetadata == this.mMailbox.getOperationChangeID()) {
/* 2053 */       return;
/*      */     }
/* 2055 */     Folder folder = getFolder();
/* 2056 */     int maxNumRevisions = getMaxRevisions();
/*      */     
/*      */ 
/* 2059 */     if (maxNumRevisions != 1) {
/* 2060 */       loadRevisions();
/*      */       
/*      */ 
/* 2063 */       if (!this.mRevisions.isEmpty()) {
/* 2064 */         MailItem lastRev = (MailItem)this.mRevisions.get(this.mRevisions.size() - 1);
/* 2065 */         if ((lastRev.mData.modContent == this.mData.modContent) && (lastRev.mData.modMetadata == this.mData.modMetadata)) {
/* 2066 */           return;
/*      */         }
/* 2068 */         int maxVer = 0;
/* 2069 */         for (MailItem rev : this.mRevisions) {
/* 2070 */           maxVer = Math.max(maxVer, rev.getVersion());
/*      */         }
/* 2072 */         if (this.mVersion <= maxVer) {
/* 2073 */           ZimbraLog.mailop.info("Item's current version is not greater than highest revision; adjusting to " + (maxVer + 1) + " (was " + this.mVersion + ")");
/*      */           
/* 2075 */           this.mVersion = (maxVer + 1);
/*      */         }
/*      */       }
/*      */       
/* 2079 */       UnderlyingData data = this.mData.clone();
/* 2080 */       data.metadata = encodeMetadata().toString();
/* 2081 */       data.setFlag(Flag.FlagInfo.UNCACHED);
/* 2082 */       this.mRevisions.add(constructItem(this.mMailbox, data));
/*      */       
/* 2084 */       this.mMailbox.updateSize(this.mData.size, isQuotaCheckRequired());
/* 2085 */       folder.updateSize(0, 0, this.mData.size);
/*      */       
/* 2087 */       ZimbraLog.mailop.debug("saving revision %d for %s", new Object[] { Integer.valueOf(this.mVersion), getMailopContext(this) });
/*      */       
/* 2089 */       DbMailItem.snapshotRevision(this, this.mVersion);
/* 2090 */       if (!isTagged(Flag.FlagInfo.VERSIONED)) {
/* 2091 */         tagChanged(this.mMailbox.getFlagById(Flag.ID_VERSIONED), true);
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 2096 */     this.mVersion += 1;
/*      */     
/*      */ 
/* 2099 */     if ((maxNumRevisions > 0) && (isTagged(Flag.FlagInfo.VERSIONED))) {
/* 2100 */       List<MailItem> revisions = loadRevisions();
/* 2101 */       int numRevsToPurge = revisions.size() - (maxNumRevisions - 1);
/* 2102 */       if (numRevsToPurge > 0) {
/* 2103 */         List<MailItem> toPurge = new ArrayList();
/* 2104 */         int numPurged = 0;
/* 2105 */         for (Iterator<MailItem> it = revisions.iterator(); (it.hasNext()) && (numPurged < numRevsToPurge); numPurged++) {
/* 2106 */           MailItem revision = (MailItem)it.next();
/* 2107 */           toPurge.add(revision);
/* 2108 */           it.remove();
/*      */         }
/*      */         
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 2115 */         int oldestRemainingSavedSequence = revisions.isEmpty() ? this.mData.modContent : ((MailItem)revisions.get(0)).getSavedSequence();
/*      */         
/* 2117 */         for (MailItem revision : toPurge) {
/* 2118 */           if (revision.getSavedSequence() < oldestRemainingSavedSequence) {
/* 2119 */             this.mMailbox.updateSize(-revision.getSize());
/* 2120 */             folder.updateSize(0, 0, -revision.getSize());
/* 2121 */             revision.markBlobForDeletion();
/*      */           }
/*      */         }
/*      */         
/* 2125 */         int highestPurgedVer = ((MailItem)toPurge.get(toPurge.size() - 1)).getVersion();
/* 2126 */         DbMailItem.purgeRevisions(this, highestPurgedVer, true);
/*      */       }
/* 2128 */       if (revisions.isEmpty()) {
/* 2129 */         tagChanged(this.mMailbox.getFlagById(Flag.ID_VERSIONED), false);
/*      */       }
/*      */     }
/*      */     
/* 2133 */     metadataChanged(updateFolderMODSEQ);
/* 2134 */     if (persist) {
/* 2135 */       saveData(new DbMailItem(this.mMailbox));
/*      */     }
/*      */   }
/*      */   
/*      */   MailItem getRevision(int version) throws ServiceException
/*      */   {
/* 2141 */     if (version == this.mVersion) {
/* 2142 */       return this;
/*      */     }
/* 2144 */     if ((version <= 0) || (version > this.mVersion) || (!isTagged(Flag.FlagInfo.VERSIONED))) {
/* 2145 */       return null;
/*      */     }
/* 2147 */     for (MailItem revision : loadRevisions()) {
/* 2148 */       if (revision.mVersion == version)
/* 2149 */         return revision;
/*      */     }
/* 2151 */     return null;
/*      */   }
/*      */   
/*      */   void purgeRevision(int version, boolean includeOlderRevisions) throws ServiceException {
/* 2155 */     if (!canAccess((short)2))
/* 2156 */       throw ServiceException.PERM_DENIED("you do not have the necessary permissions on the item");
/* 2157 */     PendingDelete info = new PendingDelete();
/* 2158 */     for (MailItem revision : loadRevisions()) {
/* 2159 */       if ((revision.getVersion() == version) || ((includeOlderRevisions) && (revision.getVersion() <= version))) {
/*      */         try {
/* 2161 */           info.blobs.add(revision.getBlob());
/* 2162 */           info.blobDigests.add(revision.getDigest());
/* 2163 */           info.size += revision.getSize();
/*      */         } catch (Exception e) {
/* 2165 */           ZimbraLog.mailbox.error("missing blob for id: " + revision.getId() + ", revision: " + revision.getVersion());
/*      */         }
/*      */       }
/*      */     }
/* 2169 */     DbMailItem.purgeRevisions(this, version, includeOlderRevisions);
/* 2170 */     getMailbox().markOtherItemDirty(info);
/* 2171 */     getMailbox().updateSize(-info.size);
/* 2172 */     this.mRevisions = null;
/*      */   }
/*      */   
/*      */   public static int purgeRevisions(Mailbox mbx, long before) throws ServiceException {
/* 2176 */     HashSet<Integer> outdatedIds = DbMailItem.getItemsWithOutdatedRevisions(mbx, (int)(before / 1000L));
/* 2177 */     int numberofpurgedrevisions = 0;
/* 2178 */     for (Iterator<Integer> iter = outdatedIds.iterator(); iter.hasNext();) {
/* 2179 */       MailItem item = getById(mbx, ((Integer)iter.next()).intValue());
/*      */       
/*      */ 
/* 2182 */       if ((item != null) && (item.getType() == Type.DOCUMENT) && (item.isTagged(Flag.FlagInfo.VERSIONED))) {
/* 2183 */         List<MailItem> revisions = item.loadRevisions();
/* 2184 */         List<MailItem> toPurge = new ArrayList();
/*      */         
/* 2186 */         Folder folder = item.getFolder();
/* 2187 */         for (Iterator<MailItem> it = revisions.iterator(); it.hasNext();) {
/* 2188 */           MailItem revision = (MailItem)it.next();
/* 2189 */           if (revision.getDate() < before) {
/* 2190 */             toPurge.add(revision);
/* 2191 */             it.remove();
/*      */           }
/*      */         }
/*      */         
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 2199 */         int oldestRemainingSavedSequence = revisions.isEmpty() ? item.mData.modContent : ((MailItem)revisions.get(0)).getSavedSequence();
/*      */         
/* 2201 */         for (MailItem revision : toPurge) {
/* 2202 */           if (revision.getSavedSequence() < oldestRemainingSavedSequence) {
/* 2203 */             item.mMailbox.updateSize(-revision.getSize());
/* 2204 */             folder.updateSize(0, 0, -revision.getSize());
/* 2205 */             revision.markBlobForDeletion();
/*      */           }
/* 2207 */           numberofpurgedrevisions++;
/*      */         }
/*      */         
/*      */ 
/* 2211 */         int highestPurgedVer = ((MailItem)toPurge.get(toPurge.size() - 1)).getVersion();
/* 2212 */         DbMailItem.purgeRevisions(item, highestPurgedVer, true);
/*      */         
/* 2214 */         if (revisions.isEmpty()) {
/* 2215 */           item.tagChanged(item.mMailbox.getFlagById(Flag.ID_VERSIONED), false);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 2220 */     return numberofpurgedrevisions;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void reanalyze(Object data, long newSize)
/*      */     throws ServiceException
/*      */   {
/* 2230 */     throw ServiceException.FAILURE("reanalysis of " + getType() + "s not supported", null);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void detach()
/*      */     throws ServiceException
/*      */   {}
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void alterUnread(boolean unread)
/*      */     throws ServiceException
/*      */   {
/* 2249 */     if (unread == isUnread()) {
/* 2250 */       return;
/*      */     }
/* 2252 */     Flag unreadFlag = Flag.FlagInfo.UNREAD.toFlag(this.mMailbox);
/* 2253 */     if (!unreadFlag.canTag(this))
/* 2254 */       throw MailServiceException.CANNOT_TAG(unreadFlag, this);
/* 2255 */     if (!canAccess((short)2)) {
/* 2256 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the item");
/*      */     }
/*      */     
/* 2259 */     markItemModified(1);
/* 2260 */     int delta = unread ? 1 : -1;
/* 2261 */     updateUnread(delta, isTagged(Flag.FlagInfo.DELETED) ? delta : 0);
/* 2262 */     metadataChanged();
/* 2263 */     DbMailItem.alterUnread(getMailbox(), ImmutableList.of(Integer.valueOf(getId())), unread);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void alterTag(Tag tag, boolean add)
/*      */     throws ServiceException
/*      */   {
/* 2287 */     if (tag == null)
/* 2288 */       throw ServiceException.FAILURE("no tag supplied when trying to tag item " + this.mId, null);
/* 2289 */     if ((!isTaggable()) || ((add) && (!tag.canTag(this))))
/* 2290 */       throw MailServiceException.CANNOT_TAG(tag, this);
/* 2291 */     if (tag.getId() == Flag.ID_UNREAD)
/* 2292 */       throw ServiceException.FAILURE("unread state must be set with alterUnread", null);
/* 2293 */     if (!canAccess((short)2)) {
/* 2294 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the item");
/*      */     }
/*      */     
/* 2297 */     if (add == isTagged(tag)) {
/* 2298 */       return;
/*      */     }
/*      */     
/* 2301 */     if (((tag instanceof Flag)) && (((Flag)tag).isSystemFlag())) {
/* 2302 */       throw MailServiceException.CANNOT_TAG(tag, this);
/*      */     }
/*      */     
/* 2305 */     MailItem parent = getParent();
/*      */     
/*      */ 
/* 2308 */     tagChanged(tag, add);
/*      */     
/*      */ 
/* 2311 */     int unreadDelta = (add ? 1 : -1) * this.mData.unreadCount;
/* 2312 */     if ((tag.trackUnread()) && (unreadDelta != 0)) {
/* 2313 */       tag.updateUnread(unreadDelta, isTagged(Flag.FlagInfo.DELETED) ? unreadDelta : 0);
/*      */     }
/*      */     
/* 2316 */     int countDelta = (add ? 1 : -1) * (isLeafNode() ? 1 : (int)this.mData.size);
/* 2317 */     tag.updateSize(countDelta, isTagged(Flag.FlagInfo.DELETED) ? countDelta : 0);
/*      */     
/*      */ 
/* 2320 */     if (tag.getId() == Flag.ID_DELETED) {
/* 2321 */       getFolder().updateSize(0, add ? 1 : -1, 0L);
/* 2322 */       updateTagSizes(0, add ? 1 : -1, 0L);
/*      */       
/* 2324 */       if (unreadDelta != 0) {
/* 2325 */         updateUnread(0, unreadDelta);
/*      */       }
/*      */     }
/*      */     
/* 2329 */     if (ZimbraLog.mailop.isDebugEnabled()) {
/* 2330 */       ZimbraLog.mailop.debug("Setting %s for %s.", new Object[] { getMailopContext(tag), getMailopContext(this) });
/*      */     }
/*      */     
/*      */ 
/* 2334 */     DbTag.alterTag(tag, Arrays.asList(new Integer[] { Integer.valueOf(getId()) }), add);
/*      */     
/*      */ 
/* 2337 */     if (parent != null) {
/* 2338 */       parent.inheritedTagChanged(tag, add);
/*      */     }
/*      */   }
/*      */   
/*      */   final void alterSystemFlag(Flag flag, boolean newValue) throws ServiceException {
/* 2343 */     if (flag == null)
/* 2344 */       throw ServiceException.FAILURE("no tag supplied when trying to tag item " + this.mId, null);
/* 2345 */     if ((flag.toBitmask() & Flag.FLAGS_SYSTEM) == 0)
/* 2346 */       throw ServiceException.FAILURE("requested to alter a non-system tag", null);
/* 2347 */     if ((newValue) && (!flag.canTag(this)))
/* 2348 */       throw MailServiceException.CANNOT_TAG(flag, this);
/* 2349 */     if (newValue == isTagged(flag)) {
/* 2350 */       return;
/*      */     }
/*      */     
/*      */ 
/* 2354 */     MailItem parent = getParent();
/*      */     
/*      */ 
/* 2357 */     tagChanged(flag, newValue);
/*      */     
/*      */ 
/* 2360 */     DbTag.alterTag(flag, Arrays.asList(new Integer[] { Integer.valueOf(getId()) }), newValue);
/*      */     
/*      */ 
/* 2363 */     if (parent != null) {
/* 2364 */       parent.inheritedTagChanged(flag, newValue);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected void tagChanged(Tag tag, boolean add)
/*      */     throws ServiceException
/*      */   {
/* 2375 */     boolean isFlag = tag instanceof Flag;
/* 2376 */     markItemModified(isFlag ? 4 : 2);
/*      */     
/* 2378 */     if ((!isFlag) || (!((Flag)tag).isSystemFlag())) {
/* 2379 */       metadataChanged();
/*      */     }
/*      */     
/* 2382 */     if (isFlag) {
/* 2383 */       if (add) {
/* 2384 */         this.mData.setFlag((Flag)tag);
/*      */       } else {
/* 2386 */         this.mData.unsetFlag((Flag)tag);
/*      */       }
/*      */     } else {
/* 2389 */       Set<String> tags = Sets.newLinkedHashSet();
/* 2390 */       Collections.addAll(tags, this.mData.getTags());
/* 2391 */       if (add) {
/* 2392 */         tags.add(tag.getName());
/*      */       } else {
/* 2394 */         tags.remove(tag.getName());
/*      */       }
/* 2396 */       this.mData.setTags(tags.isEmpty() ? null : new Tag.NormalizedTags(tags));
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   protected void inheritedTagChanged(Tag tag, boolean add)
/*      */     throws ServiceException
/*      */   {}
/*      */   
/*      */ 
/*      */   protected void updateUnread(int delta, int deletedDelta)
/*      */     throws ServiceException
/*      */   {
/* 2409 */     if ((delta == 0) || (!trackUnread())) {
/* 2410 */       return;
/*      */     }
/*      */     
/* 2413 */     markItemModified(1);
/* 2414 */     this.mData.unreadCount += delta;
/* 2415 */     if (this.mData.unreadCount < 0) {
/* 2416 */       throw ServiceException.FAILURE("inconsistent state: unread < 0 for item " + this.mId, null);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected void updateTagUnread(int delta, int deletedDelta)
/*      */     throws ServiceException
/*      */   {
/* 2428 */     if (((delta == 0) && (deletedDelta == 0)) || (!isTaggable())) {
/* 2429 */       return;
/*      */     }
/* 2431 */     String[] tags = this.mData.getTags();
/* 2432 */     for (String name : tags) {
/*      */       try {
/* 2434 */         this.mMailbox.getTagByName(name).updateUnread(delta, deletedDelta);
/*      */       } catch (MailServiceException.NoSuchItemException nsie) {
/* 2436 */         ZimbraLog.mailbox.warn("item %d has nonexistent tag %s", new Object[] { Integer.valueOf(this.mId), name });
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected void updateTagSizes(int countDelta, int deletedDelta, long sizeDelta)
/*      */     throws ServiceException
/*      */   {
/* 2450 */     if (((countDelta == 0) && (deletedDelta == 0) && (sizeDelta == 0L)) || (!isTaggable())) {
/* 2451 */       return;
/*      */     }
/* 2453 */     String[] tags = this.mData.getTags();
/* 2454 */     for (String name : tags) {
/*      */       try {
/* 2456 */         this.mMailbox.getTagByName(name).updateSize(countDelta, deletedDelta);
/*      */       } catch (MailServiceException.NoSuchItemException nsie) {
/* 2458 */         ZimbraLog.mailbox.warn("item %d has nonexistent tag %s", new Object[] { Integer.valueOf(this.mId), name });
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void setTags(int flags, Tag.NormalizedTags ntags)
/*      */     throws ServiceException
/*      */   {
/* 2478 */     if (!canAccess((short)2)) {
/* 2479 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the item");
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 2485 */     flags = flags & (Flag.FLAGS_SYSTEM ^ 0xFFFFFFFF) | getFlagBitmask() & Flag.FLAGS_SYSTEM;
/*      */     Iterator i$;
/* 2487 */     if (flags != this.mData.getFlags()) {
/* 2488 */       markItemModified(4);
/* 2489 */       for (i$ = Flag.toId(flags ^ this.mData.getFlags()).iterator(); i$.hasNext();) { int flagId = ((Integer)i$.next()).intValue();
/* 2490 */         Flag flag = Flag.of(this.mMailbox, flagId);
/* 2491 */         if (flag != null) {
/* 2492 */           alterTag(flag, !isTagged(flag));
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 2498 */     if (ntags.getTags() != this.mData.getTags()) {
/* 2499 */       Set<String> removed = Sets.newHashSet(this.mData.getTags());Set<String> added = Sets.newHashSet(ntags.getTags());
/* 2500 */       removed.removeAll(added);
/* 2501 */       added.removeAll(Arrays.asList(this.mData.getTags()));
/*      */       
/* 2503 */       for (String tagName : removed) {
/*      */         try {
/* 2505 */           alterTag(this.mMailbox.getTagByName(tagName), false);
/*      */         } catch (MailServiceException.NoSuchItemException nsie) {}
/*      */       }
/* 2508 */       for (String tagName : added) {
/*      */         try {
/* 2510 */           alterTag(this.mMailbox.getTagByName(tagName), true);
/*      */         }
/*      */         catch (MailServiceException.NoSuchItemException nsie) {}
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   MailItem copy(Folder folder, int copyId, String copyUuid, MailItem parent)
/*      */     throws IOException, ServiceException
/*      */   {
/* 2541 */     if (!isCopyable())
/* 2542 */       throw MailServiceException.CANNOT_COPY(this.mId);
/* 2543 */     if (!folder.canContain(this)) {
/* 2544 */       throw MailServiceException.CANNOT_CONTAIN();
/*      */     }
/* 2546 */     if (!canAccess((short)1))
/* 2547 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the item");
/* 2548 */     if (!folder.canAccess((short)4)) {
/* 2549 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the target folder");
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 2554 */     boolean inDumpster = inDumpster();
/* 2555 */     boolean shareIndex = (!inDumpster) && (!isMutable()) && (getIndexStatus() == IndexStatus.DONE) && (!folder.inSpam());
/*      */     
/*      */ 
/* 2558 */     boolean detach = (parent == null) || (isTagged(Flag.FlagInfo.DRAFT)) || (inSpam() != folder.inSpam());
/* 2559 */     parent = detach ? null : parent;
/*      */     
/* 2561 */     if ((shareIndex) && (!isTagged(Flag.FlagInfo.COPIED))) {
/* 2562 */       alterSystemFlag(this.mMailbox.getFlagById(Flag.ID_COPIED), true);
/* 2563 */       if (ZimbraLog.mailop.isDebugEnabled()) {
/* 2564 */         ZimbraLog.mailop.debug("setting copied flag for %s", new Object[] { getMailopContext(this) });
/*      */       }
/*      */     }
/* 2567 */     StoreManager sm = StoreManager.getInstance();
/*      */     
/*      */ 
/* 2570 */     String locator = null;
/* 2571 */     MailboxBlob srcMblob = getBlob();
/* 2572 */     if (srcMblob != null) {
/* 2573 */       MailboxBlob mblob = sm.copy(srcMblob, this.mMailbox, copyId, this.mMailbox.getOperationChangeID());
/* 2574 */       this.mMailbox.markOtherItemDirty(mblob);
/* 2575 */       locator = mblob.getLocator();
/*      */     }
/*      */     
/* 2578 */     UnderlyingData data = this.mData.duplicate(copyId, copyUuid, folder.getId(), locator);
/* 2579 */     data.parentId = (detach ? -1 : parent.mId);
/* 2580 */     data.indexId = (shareIndex ? getIndexId() : IndexStatus.DEFERRED.id());
/* 2581 */     if (!shareIndex) {
/* 2582 */       data.unsetFlag(Flag.FlagInfo.COPIED);
/*      */     }
/* 2584 */     data.unsetFlag(Flag.FlagInfo.IN_DUMPSTER);
/* 2585 */     data.metadata = encodeMetadata().toString();
/* 2586 */     data.contentChanged(this.mMailbox);
/*      */     
/* 2588 */     ZimbraLog.mailop.info("Copying %s: copyId=%d, folderId=%d, folderName=%s, parentId=%d.", new Object[] { getMailopContext(this), Integer.valueOf(copyId), Integer.valueOf(folder.getId()), folder.getName(), Integer.valueOf(data.parentId) });
/*      */     
/* 2590 */     String prevFolders = DbMailItem.copy(this, copyId, copyUuid, folder, data.indexId, data.parentId, data.locator, data.metadata, inDumpster);
/* 2591 */     if (!StringUtil.isNullOrEmpty(prevFolders)) {
/* 2592 */       data.setPrevFolders(prevFolders);
/*      */     }
/* 2594 */     if ((this instanceof CalendarItem)) {
/* 2595 */       DbMailItem.copyCalendarItem((CalendarItem)this, copyId, inDumpster);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 2600 */     if (inDumpster) {
/* 2601 */       for (MailItem revision : loadRevisions()) {
/* 2602 */         MailboxBlob srcRevBlob = revision.getBlob();
/* 2603 */         String revLocator = null;
/* 2604 */         if (srcRevBlob != null) {
/* 2605 */           MailboxBlob copyRevBlob = sm.copy(srcRevBlob, this.mMailbox, copyId, revision.getSavedSequence());
/* 2606 */           this.mMailbox.markOtherItemDirty(copyRevBlob);
/* 2607 */           revLocator = copyRevBlob.getLocator();
/*      */         }
/* 2609 */         DbMailItem.copyRevision(revision, copyId, revLocator, inDumpster);
/*      */       }
/*      */     }
/*      */     
/* 2613 */     MailItem copy = constructItem(this.mMailbox, data);
/* 2614 */     copy.finishCreation(parent);
/*      */     
/* 2616 */     if (!shareIndex) {
/* 2617 */       this.mMailbox.index.add(copy);
/*      */     }
/*      */     
/* 2620 */     return copy;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   MailItem icopy(Folder target, int copyId, String copyUuid)
/*      */     throws IOException, ServiceException
/*      */   {
/* 2649 */     if (!isCopyable())
/* 2650 */       throw MailServiceException.CANNOT_COPY(this.mId);
/* 2651 */     if (!target.canContain(this)) {
/* 2652 */       throw MailServiceException.CANNOT_CONTAIN();
/*      */     }
/*      */     
/* 2655 */     if (!canAccess((short)1))
/* 2656 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the item");
/* 2657 */     if (!target.canAccess((short)4)) {
/* 2658 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the target folder");
/*      */     }
/*      */     
/* 2661 */     MailItem parent = getParent();
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 2675 */     String locator = null;
/* 2676 */     MailboxBlob srcMblob = getBlob();
/* 2677 */     if (srcMblob != null) {
/* 2678 */       StoreManager sm = StoreManager.getInstance();
/* 2679 */       MailboxBlob mblob = sm.copy(srcMblob, this.mMailbox, copyId, this.mMailbox.getOperationChangeID());
/* 2680 */       this.mMailbox.markOtherItemDirty(mblob);
/* 2681 */       locator = mblob.getLocator();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 2686 */     boolean shareIndex = (!isMutable()) && (getIndexStatus() == IndexStatus.DONE) && (!target.inSpam());
/*      */     
/* 2688 */     UnderlyingData data = this.mData.duplicate(copyId, copyUuid, target.getId(), locator);
/* 2689 */     data.metadata = encodeMetadata().toString();
/* 2690 */     data.imapId = copyId;
/* 2691 */     data.indexId = (shareIndex ? getIndexId() : IndexStatus.DEFERRED.id());
/* 2692 */     data.contentChanged(this.mMailbox);
/*      */     
/* 2694 */     ZimbraLog.mailop.info("Performing IMAP copy of %s: copyId=%d, folderId=%d, folderName=%s, parentId=%d.", new Object[] { getMailopContext(this), Integer.valueOf(copyId), Integer.valueOf(target.getId()), target.getName(), Integer.valueOf(data.parentId) });
/*      */     
/* 2696 */     DbMailItem.icopy(this, data, shareIndex);
/*      */     
/* 2698 */     MailItem copy = constructItem(this.mMailbox, data);
/* 2699 */     copy.finishCreation(null);
/*      */     
/* 2701 */     if ((shareIndex) && (!isTagged(Flag.FlagInfo.COPIED))) {
/* 2702 */       Flag copiedFlag = this.mMailbox.getFlagById(Flag.ID_COPIED);
/* 2703 */       tagChanged(copiedFlag, true);
/* 2704 */       copy.tagChanged(copiedFlag, true);
/* 2705 */       if (parent != null) {
/* 2706 */         parent.inheritedTagChanged(copiedFlag, true);
/*      */       }
/*      */     }
/* 2709 */     if ((parent != null) && (parent.getId() > 0)) {
/* 2710 */       markItemModified(512);
/* 2711 */       parent.markItemModified(1024);
/* 2712 */       this.mData.parentId = (this.mData.type == Type.MESSAGE.toByte() ? -this.mId : -1);
/* 2713 */       metadataChanged();
/*      */     }
/*      */     
/* 2716 */     if (!shareIndex) {
/* 2717 */       this.mMailbox.index.add(copy);
/*      */     }
/*      */     
/* 2720 */     return copy;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 2729 */   private static final Set<String> RESERVED_NAMES = ImmutableSet.of(".", "..");
/*      */   
/*      */   public static final int MAX_NAME_LENGTH = 255;
/*      */   
/*      */   private static final int UNREAD_ITEM_BATCH_SIZE = 500;
/*      */   
/*      */   private static final String CUSTOM_META_PREFIX = "xd.";
/*      */   
/*      */   private static final String CN_ID = "id";
/*      */   
/*      */   private static final String CN_TYPE = "type";
/*      */   private static final String CN_PARENT_ID = "parent_id";
/*      */   private static final String CN_FOLDER_ID = "folder_id";
/*      */   private static final String CN_DATE = "date";
/*      */   private static final String CN_SIZE = "size";
/*      */   private static final String CN_REVISION = "rev";
/*      */   
/*      */   static String validateItemName(String name)
/*      */     throws ServiceException
/*      */   {
/* 2749 */     if ((name == null) || (name != StringUtil.stripControlCharacters(name)) || (name.matches(".*[:/\"\t\r\n].*"))) {
/* 2750 */       throw MailServiceException.INVALID_NAME(name);
/*      */     }
/*      */     
/*      */ 
/* 2754 */     String trimmed = StringUtil.trimTrailingSpaces(name);
/* 2755 */     if ((trimmed.isEmpty()) || (trimmed.length() > 255) || (RESERVED_NAMES.contains(trimmed))) {
/* 2756 */       throw MailServiceException.INVALID_NAME(name);
/*      */     }
/* 2758 */     return trimmed;
/*      */   }
/*      */   
/*      */   public static String normalizeItemName(String name) {
/*      */     try {
/* 2763 */       return validateItemName(name);
/*      */     } catch (ServiceException e) {
/* 2765 */       String normalized = StringUtil.stripControlCharacters(name);
/* 2766 */       if (normalized == null) {
/* 2767 */         normalized = "";
/*      */       }
/* 2769 */       if (normalized.length() > 255) {
/* 2770 */         normalized = normalized.substring(0, 255);
/*      */       }
/* 2772 */       if (normalized.matches(".*[:/\"\t\r\n].*")) {
/* 2773 */         normalized = normalized.replaceAll("[:/\"\t\r\n]", "");
/*      */       }
/* 2775 */       normalized = StringUtil.trimTrailingSpaces(normalized);
/* 2776 */       if (RESERVED_NAMES.contains(normalized)) {
/* 2777 */         normalized = "";
/*      */       }
/*      */       
/* 2780 */       if (normalized.trim().equals("")) {}
/* 2781 */       return "item" + System.currentTimeMillis();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void rename(String name)
/*      */     throws ServiceException
/*      */   {
/* 2802 */     rename(name, getFolder());
/*      */   }
/*      */   
/*      */ 
/*      */   private static final String CN_BLOB_DIGEST = "digest";
/*      */   
/*      */   private static final String CN_UNREAD_COUNT = "unread";
/*      */   
/*      */   private static final String CN_FLAGS = "flags";
/*      */   
/*      */   private static final String CN_TAGS = "tags";
/*      */   
/*      */   private static final String CN_SUBJECT = "subject";
/*      */   
/*      */   private static final String CN_NAME = "name";
/*      */   
/*      */   private static final String CN_COLOR = "color";
/*      */   
/*      */   private static final String CN_METADATA_VERSION = "meta_version";
/*      */   private static final String CN_VERSION = "version";
/*      */   private static final String CN_IMAP_ID = "imap_id";
/*      */   void rename(String newName, Folder target)
/*      */     throws ServiceException
/*      */   {
/* 2826 */     String name = validateItemName(newName);
/*      */     
/* 2828 */     boolean renamed = !name.equals(this.mData.name);
/* 2829 */     boolean moved = target != getFolder();
/*      */     
/* 2831 */     if ((!renamed) && (!moved)) {
/* 2832 */       return;
/*      */     }
/* 2834 */     if ((moved) && (target.getId() != 3) && (target.getId() != 4) && (!target.canAccess((short)4)))
/* 2835 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the target item");
/* 2836 */     if ((moved) && (!canAccess((short)8)))
/* 2837 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the item");
/* 2838 */     if ((renamed) && (!canAccess((short)2))) {
/* 2839 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the item");
/*      */     }
/*      */     
/* 2842 */     if (renamed) {
/* 2843 */       if (this.mData.name == null)
/* 2844 */         throw MailServiceException.CANNOT_RENAME(getType());
/* 2845 */       if (!isMutable()) {
/* 2846 */         throw MailServiceException.IMMUTABLE_OBJECT(this.mId);
/*      */       }
/*      */       try
/*      */       {
/* 2850 */         MailItem conflict = this.mMailbox.getItemByPath(null, name, target.getId());
/* 2851 */         if ((conflict != null) && (conflict != this)) {
/* 2852 */           throw MailServiceException.ALREADY_EXISTS(name);
/*      */         }
/*      */       }
/*      */       catch (MailServiceException.NoSuchItemException nsie) {}
/* 2856 */       if (ZimbraLog.mailop.isDebugEnabled()) {
/* 2857 */         ZimbraLog.mailop.debug("renaming " + getMailopContext(this) + " to " + name);
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 2863 */       markItemModified(4096);
/* 2864 */       this.mData.name = name;
/* 2865 */       this.mData.setSubject(name);
/* 2866 */       this.mData.dateChanged = this.mMailbox.getOperationTimestamp();
/* 2867 */       metadataChanged();
/*      */       
/* 2869 */       saveName(target.getId());
/*      */     }
/*      */     
/* 2872 */     if (moved) {
/* 2873 */       move(target);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean move(Folder target)
/*      */     throws ServiceException
/*      */   {
/* 2898 */     if (this.mData.folderId == target.getId()) {
/* 2899 */       return false;
/*      */     }
/* 2901 */     markItemModified(256);
/* 2902 */     if (!isMovable()) {
/* 2903 */       throw MailServiceException.IMMUTABLE_OBJECT(this.mId);
/*      */     }
/* 2905 */     if (!target.canContain(this)) {
/* 2906 */       throw MailServiceException.CANNOT_CONTAIN();
/*      */     }
/* 2908 */     Folder oldFolder = getFolder();
/* 2909 */     if (!oldFolder.canAccess((short)8)) {
/* 2910 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the source folder");
/*      */     }
/* 2912 */     if ((target.getId() != 3) && (target.getId() != 4) && (!target.canAccess((short)4)))
/*      */     {
/* 2914 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the target folder");
/*      */     }
/* 2916 */     if (isLeafNode()) {
/* 2917 */       boolean isDeleted = isTagged(Flag.FlagInfo.DELETED);
/* 2918 */       oldFolder.updateSize(-1, isDeleted ? -1 : 0, -getTotalSize());
/* 2919 */       target.updateSize(1, isDeleted ? 1 : 0, getTotalSize());
/*      */     }
/*      */     
/* 2922 */     if ((!inTrash()) && (target.inTrash()))
/*      */     {
/* 2924 */       if (this.mData.unreadCount > 0) {
/* 2925 */         alterUnread(false);
/*      */       }
/*      */     } else {
/* 2928 */       boolean isDeleted = isTagged(Flag.FlagInfo.DELETED);
/* 2929 */       oldFolder.updateUnread(-this.mData.unreadCount, isDeleted ? -this.mData.unreadCount : 0);
/* 2930 */       target.updateUnread(this.mData.unreadCount, isDeleted ? this.mData.unreadCount : 0);
/*      */     }
/*      */     
/* 2933 */     if ((!inSpam()) && (target.inSpam())) {
/* 2934 */       detach();
/*      */     }
/*      */     
/* 2937 */     if ((inSpam()) && (!target.inSpam()) && (getIndexStatus() == IndexStatus.DONE)) {
/* 2938 */       this.mMailbox.index.add(this);
/*      */     }
/*      */     
/* 2941 */     ZimbraLog.mailop.info("moving " + getMailopContext(this) + " to " + getMailopContext(target));
/* 2942 */     DbMailItem.setFolder(this, target);
/* 2943 */     folderChanged(target, 0);
/* 2944 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void folderChanged(Folder newFolder, int imapId)
/*      */     throws ServiceException
/*      */   {
/* 2955 */     if (this.mData.folderId == newFolder.getId()) {
/* 2956 */       return;
/*      */     }
/* 2958 */     markItemModified(256);
/* 2959 */     this.mData.folderId = newFolder.getId();
/* 2960 */     this.mData.imapId = (this.mMailbox.isTrackingImap() ? imapId : this.mData.imapId);
/* 2961 */     metadataChanged();
/*      */   }
/*      */   
/*      */   void addChild(MailItem child) throws ServiceException {
/* 2965 */     markItemModified(1024);
/* 2966 */     if (!canParent(child)) {
/* 2967 */       throw MailServiceException.CANNOT_PARENT();
/*      */     }
/* 2969 */     if (this.mMailbox != child.getMailbox()) {
/* 2970 */       throw MailServiceException.WRONG_MAILBOX();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   void removeChild(MailItem child)
/*      */     throws ServiceException
/*      */   {
/* 2978 */     markItemModified(1024);
/*      */     
/*      */ 
/* 2981 */     if (child.mData.parentId == this.mId) {
/* 2982 */       child.mData.parentId = -1;
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   static class TemporaryIndexingException
/*      */     extends Exception
/*      */   {
/*      */     private static final long serialVersionUID = 730987946876783701L;
/*      */   }
/*      */   
/*      */ 
/*      */   public static class PendingDelete
/*      */   {
/*      */     public int deletedTypes;
/*      */     
/*      */     public boolean incomplete;
/*      */     
/*      */     public long size;
/*      */     
/*      */     public int contacts;
/* 3003 */     public TypedIdList itemIds = new TypedIdList();
/*      */     
/*      */ 
/*      */ 
/* 3007 */     public List<Integer> unreadIds = new ArrayList(1);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public List<Integer> cascadeIds;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 3018 */     public Set<Integer> modifiedIds = new HashSet(2);
/*      */     
/*      */ 
/* 3021 */     public final List<Integer> indexIds = new ArrayList(1);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     public Set<Integer> sharedIndex;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/* 3031 */     public List<MailboxBlob> blobs = new ArrayList(1);
/*      */     
/*      */ 
/*      */ 
/* 3035 */     public Map<Integer, DbMailItem.LocationCount> folderCounts = Maps.newHashMapWithExpectedSize(1);
/*      */     
/*      */ 
/*      */ 
/* 3039 */     public Map<String, DbMailItem.LocationCount> tagCounts = Maps.newHashMapWithExpectedSize(1);
/*      */     
/*      */ 
/* 3042 */     public Set<String> blobDigests = new HashSet(2);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     PendingDelete add(PendingDelete other)
/*      */     {
/* 3049 */       if (other != null) {
/* 3050 */         this.deletedTypes |= other.deletedTypes;
/* 3051 */         this.incomplete |= other.incomplete;
/*      */         
/* 3053 */         this.size += other.size;
/* 3054 */         this.contacts += other.contacts;
/*      */         
/* 3056 */         this.itemIds.addAll(other.itemIds);
/* 3057 */         this.unreadIds.addAll(other.unreadIds);
/* 3058 */         this.modifiedIds.addAll(other.modifiedIds);
/* 3059 */         this.indexIds.addAll(other.indexIds);
/* 3060 */         this.blobs.addAll(other.blobs);
/* 3061 */         this.blobDigests.addAll(other.blobDigests);
/*      */         
/* 3063 */         if (other.cascadeIds != null) {
/* 3064 */           (this.cascadeIds == null ? (this.cascadeIds = new ArrayList(other.cascadeIds.size())) : this.cascadeIds).addAll(other.cascadeIds);
/*      */         }
/* 3066 */         if (other.sharedIndex != null) {
/* 3067 */           (this.sharedIndex == null ? (this.sharedIndex = new HashSet(other.sharedIndex.size())) : this.sharedIndex).addAll(other.sharedIndex);
/*      */         }
/*      */         
/* 3070 */         for (Map.Entry<Integer, DbMailItem.LocationCount> entry : other.folderCounts.entrySet()) {
/* 3071 */           DbMailItem.LocationCount lcount = (DbMailItem.LocationCount)this.folderCounts.get(entry.getKey());
/* 3072 */           if (lcount == null) {
/* 3073 */             this.folderCounts.put(entry.getKey(), new DbMailItem.LocationCount((DbMailItem.LocationCount)entry.getValue()));
/*      */           } else {
/* 3075 */             lcount.increment((DbMailItem.LocationCount)entry.getValue());
/*      */           }
/*      */         }
/* 3078 */         for (Map.Entry<String, DbMailItem.LocationCount> entry : other.tagCounts.entrySet()) {
/* 3079 */           DbMailItem.LocationCount lcount = (DbMailItem.LocationCount)this.tagCounts.get(entry.getKey());
/* 3080 */           if (lcount == null) {
/* 3081 */             this.tagCounts.put(entry.getKey(), new DbMailItem.LocationCount((DbMailItem.LocationCount)entry.getValue()));
/*      */           } else {
/* 3083 */             lcount.increment((DbMailItem.LocationCount)entry.getValue());
/*      */           }
/*      */         }
/*      */       }
/* 3087 */       return this;
/*      */     }
/*      */   }
/*      */   
/*      */   void delete() throws ServiceException {
/* 3092 */     delete(true);
/*      */   }
/*      */   
/*      */   void delete(boolean writeTombstones) throws ServiceException {
/* 3096 */     if (!isDeletable()) {
/* 3097 */       throw MailServiceException.IMMUTABLE_OBJECT(this.mId);
/*      */     }
/*      */     
/*      */ 
/* 3101 */     PendingDelete info = getDeletionInfo();
/* 3102 */     assert ((info != null) && (info.itemIds != null));
/* 3103 */     if (info.incomplete)
/*      */     {
/* 3105 */       info.itemIds.remove(getType(), Integer.valueOf(this.mId));
/*      */     }
/*      */     
/* 3108 */     delete(this.mMailbox, info, this, writeTombstones, inDumpster());
/*      */   }
/*      */   
/*      */   static void delete(Mailbox mbox, PendingDelete info, MailItem item, boolean writeTombstones, boolean fromDumpster)
/*      */     throws ServiceException
/*      */   {
/* 3114 */     if (info.itemIds.isEmpty()) {
/* 3115 */       return;
/*      */     }
/* 3117 */     mbox.markItemDeleted(info.itemIds);
/*      */     
/* 3119 */     MailItem parent = null;
/*      */     
/* 3121 */     if ((item != null) && (!info.incomplete)) {
/* 3122 */       item.markItemDeleted();
/* 3123 */       parent = item.getParent();
/*      */     }
/*      */     
/* 3126 */     if (!fromDumpster)
/*      */     {
/* 3128 */       mbox.updateSize(-info.size);
/* 3129 */       mbox.updateContactCount(-info.contacts);
/*      */       
/*      */ 
/* 3132 */       if (item != null) {
/* 3133 */         item.propagateDeletion(info);
/*      */       }
/*      */       else {
/* 3136 */         List<UnderlyingData> unreadData = DbMailItem.getById(mbox, info.unreadIds, Type.MESSAGE);
/* 3137 */         for (UnderlyingData data : unreadData)
/*      */         {
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3148 */           MailItem unread = mbox.getItem(data);
/* 3149 */           unread.updateUnread(-data.unreadCount, unread.isTagged(Flag.FlagInfo.DELETED) ? -data.unreadCount : 0);
/*      */         }
/*      */         
/* 3152 */         for (Map.Entry<Integer, DbMailItem.LocationCount> entry : info.folderCounts.entrySet()) {
/* 3153 */           int folderID = ((Integer)entry.getKey()).intValue();
/* 3154 */           DbMailItem.LocationCount lcount = (DbMailItem.LocationCount)entry.getValue();
/* 3155 */           mbox.getFolderById(folderID).updateSize(-lcount.count, -lcount.deleted, -lcount.size);
/*      */         }
/* 3157 */         for (Map.Entry<String, DbMailItem.LocationCount> entry : info.tagCounts.entrySet()) {
/* 3158 */           String tag = (String)entry.getKey();
/* 3159 */           DbMailItem.LocationCount lcount = (DbMailItem.LocationCount)entry.getValue();
/* 3160 */           mbox.getTagByName(tag).updateSize(-lcount.count, -lcount.deleted);
/*      */         }
/*      */         
/*      */ 
/* 3164 */         info.cascadeIds = DbMailItem.markDeletionTargets(mbox, info.itemIds.getIds(EnumSet.of(Type.MESSAGE, Type.CHAT)), info.modifiedIds);
/* 3165 */         if (info.cascadeIds != null) {
/* 3166 */           info.modifiedIds.removeAll(info.cascadeIds);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 3172 */     if (ZimbraLog.mailop.isInfoEnabled()) {
/* 3173 */       if (item != null) {
/* 3174 */         if ((item instanceof VirtualConversation)) {
/* 3175 */           ZimbraLog.mailop.info("Deleting Message (id=%d).", new Object[] { Integer.valueOf(((VirtualConversation)item).getMessageId()) });
/*      */         } else {
/* 3177 */           ZimbraLog.mailop.info("Deleting %s.", new Object[] { getMailopContext(item) });
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 3182 */       int itemId = item == null ? 0 : Math.abs(item.getId());
/* 3183 */       Set<Integer> idSet = new TreeSet();
/* 3184 */       for (Iterator i$ = info.itemIds.getAllIds().iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/* 3185 */         id = Math.abs(id);
/* 3186 */         if (id != itemId) {
/* 3187 */           idSet.add(Integer.valueOf(id));
/*      */         }
/* 3189 */         if (idSet.size() >= 200)
/*      */         {
/* 3191 */           ZimbraLog.mailop.info("Deleting items: %s.", new Object[] { StringUtil.join(",", idSet) });
/* 3192 */           idSet.clear();
/*      */         }
/*      */       }
/* 3195 */       if (idSet.size() > 0)
/*      */       {
/* 3197 */         ZimbraLog.mailop.info("Deleting items: %s.", new Object[] { StringUtil.join(",", idSet) });
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 3202 */     DbMailItem.delete(mbox, item, info, fromDumpster);
/*      */     
/*      */ 
/* 3205 */     if (item != null) {
/* 3206 */       item.purgeCache(info, !info.incomplete);
/* 3207 */       if (parent != null) {
/* 3208 */         parent.removeChild(item);
/*      */       }
/* 3210 */     } else if (!info.itemIds.isEmpty())
/*      */     {
/* 3212 */       for (Iterator i$ = info.itemIds.getAllIds().iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/* 3213 */         mbox.uncacheItem(Integer.valueOf(itemId));
/*      */       }
/*      */       
/* 3216 */       if (!info.modifiedIds.isEmpty()) {
/* 3217 */         mbox.purge(Type.CONVERSATION);
/*      */         
/* 3219 */         if (mbox.hasListeners(Session.Type.SOAP)) {
/* 3220 */           for (MailItem conv : mbox.getItemById(info.modifiedIds, Type.CONVERSATION)) {
/* 3221 */             ((Conversation)conv).getSenderList();
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 3228 */     if ((info.cascadeIds != null) && (!info.cascadeIds.isEmpty())) {
/* 3229 */       for (Integer convId : info.cascadeIds) {
/* 3230 */         mbox.markItemDeleted(Type.CONVERSATION, convId.intValue());
/* 3231 */         mbox.uncacheItem(convId);
/*      */       }
/*      */       try {
/* 3234 */         DbMailItem.delete(mbox, info.cascadeIds, false);
/*      */       } catch (ServiceException se) {
/* 3236 */         MailboxErrorUtil.handleCascadeFailure(mbox, info.cascadeIds, se);
/*      */       }
/*      */       
/* 3239 */       for (Integer id : info.cascadeIds) {
/* 3240 */         info.itemIds.add(Type.CONVERSATION, id, null);
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 3245 */     if ((info.sharedIndex != null) && (!info.sharedIndex.isEmpty())) {
/* 3246 */       DbMailItem.resolveSharedIndex(mbox, info);
/*      */     }
/*      */     
/* 3249 */     mbox.markOtherItemDirty(info);
/*      */     
/*      */ 
/* 3252 */     if ((writeTombstones) && (mbox.isTrackingSync()) && (!info.itemIds.isEmpty()) && (!fromDumpster)) {
/* 3253 */       DbMailItem.writeTombstones(mbox, info.itemIds);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   static String getMailopContext(MailItem item)
/*      */   {
/* 3260 */     if ((item == null) || (!ZimbraLog.mailop.isInfoEnabled()))
/* 3261 */       return "<undefined>";
/* 3262 */     if (((item instanceof Folder)) || ((item instanceof Tag)) || ((item instanceof WikiItem)))
/* 3263 */       return String.format("%s %s (id=%d)", new Object[] { item.getClass().getSimpleName(), item.getName(), Integer.valueOf(item.getId()) });
/* 3264 */     if ((item instanceof Contact)) {
/* 3265 */       String email = ((Contact)item).get(ContactConstants.A_email);
/* 3266 */       if (StringUtil.isNullOrEmpty(email)) {
/* 3267 */         email = "<undefined>";
/*      */       }
/* 3269 */       return String.format("%s %s (id=%d)", new Object[] { item.getClass().getSimpleName(), email, Integer.valueOf(item.getId()) });
/*      */     }
/* 3271 */     return String.format("%s (id=%d)", new Object[] { item.getClass().getSimpleName(), Integer.valueOf(item.getId()) });
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   PendingDelete getDeletionInfo()
/*      */     throws ServiceException
/*      */   {
/* 3284 */     if (!canAccess((short)8)) {
/* 3285 */       throw ServiceException.PERM_DENIED("you do not have the required rights on the item");
/*      */     }
/*      */     
/* 3288 */     Integer id = Integer.valueOf(this.mId);
/* 3289 */     PendingDelete info = new PendingDelete();
/* 3290 */     info.size = getTotalSize();
/* 3291 */     info.itemIds.add(getType(), id, this.mData.uuid);
/*      */     
/* 3293 */     if (!inDumpster()) {
/* 3294 */       if ((this.mData.unreadCount != 0) && (this.mMailbox.getFlagById(Flag.ID_UNREAD).canTag(this))) {
/* 3295 */         info.unreadIds.add(id);
/*      */       }
/* 3297 */       boolean isDeleted = isTagged(Flag.FlagInfo.DELETED);
/* 3298 */       info.folderCounts.put(Integer.valueOf(getFolderId()), new DbMailItem.LocationCount(1, isDeleted ? 1 : 0, info.size));
/* 3299 */       for (String tag : this.mData.getTags()) {
/* 3300 */         info.tagCounts.put(tag, new DbMailItem.LocationCount(1, isDeleted ? 1 : 0, info.size));
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 3308 */     if ((!getMailbox().dumpsterEnabled()) || (inDumpster()) || (this.mData.folderId == 6) || ((inSpam()) && (!getMailbox().useDumpsterForSpam())))
/*      */     {
/* 3310 */       if (getIndexStatus() != IndexStatus.NO) {
/* 3311 */         int indexId = getIndexStatus() == IndexStatus.DONE ? this.mData.indexId : this.mData.id;
/* 3312 */         if (isTagged(Flag.FlagInfo.COPIED)) {
/* 3313 */           info.sharedIndex = Sets.newHashSet(new Integer[] { Integer.valueOf(indexId) });
/*      */         } else {
/* 3315 */           info.indexIds.add(Integer.valueOf(indexId));
/*      */         }
/*      */       }
/*      */       
/* 3319 */       List<MailItem> items = new ArrayList(3);
/* 3320 */       items.add(this);
/* 3321 */       items.addAll(loadRevisions());
/* 3322 */       for (MailItem revision : items) {
/*      */         try {
/* 3324 */           info.blobs.add(revision.getBlob());
/*      */         } catch (Exception e) {
/* 3326 */           ZimbraLog.mailbox.error("missing blob for id: " + this.mId + ", change: " + revision.getSavedSequence());
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 3331 */     return info;
/*      */   }
/*      */   
/*      */   void propagateDeletion(PendingDelete info)
/*      */     throws ServiceException
/*      */   {
/* 3337 */     if (!info.unreadIds.isEmpty()) {
/* 3338 */       int i = 0; for (int count = info.unreadIds.size(); i < count; i += 500) {
/* 3339 */         List<Integer> batch = info.unreadIds.subList(i, Math.min(i + 500, count));
/* 3340 */         for (UnderlyingData data : DbMailItem.getById(this.mMailbox, batch, Type.MESSAGE)) {
/* 3341 */           Message msg = (Message)this.mMailbox.getItem(data);
/* 3342 */           if (msg.isUnread()) {
/* 3343 */             msg.updateUnread(-1, msg.isTagged(Flag.FlagInfo.DELETED) ? -1 : 0);
/*      */           }
/* 3345 */           this.mMailbox.uncache(msg);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 3350 */     for (Map.Entry<Integer, DbMailItem.LocationCount> entry : info.folderCounts.entrySet()) {
/* 3351 */       Folder folder = this.mMailbox.getFolderById(((Integer)entry.getKey()).intValue());
/* 3352 */       DbMailItem.LocationCount lcount = (DbMailItem.LocationCount)entry.getValue();
/* 3353 */       folder.updateSize(-lcount.count, -lcount.deleted, -lcount.size);
/*      */     }
/* 3355 */     for (Map.Entry<String, DbMailItem.LocationCount> entry : info.tagCounts.entrySet()) {
/* 3356 */       Tag tag = this.mMailbox.getTagByName((String)entry.getKey());
/* 3357 */       DbMailItem.LocationCount lcount = (DbMailItem.LocationCount)entry.getValue();
/* 3358 */       tag.updateSize(-lcount.count, -lcount.deleted);
/*      */     }
/*      */   }
/*      */   
/*      */   void purgeCache(PendingDelete info, boolean purgeItem) throws ServiceException { Iterator i$;
/* 3363 */     if (purgeItem) {
/* 3364 */       this.mMailbox.uncache(this);
/* 3365 */       for (i$ = info.itemIds.getAllIds().iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/* 3366 */         this.mMailbox.uncacheItem(Integer.valueOf(itemId));
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected boolean trackUserAgentInMetadata()
/*      */   {
/* 3375 */     return false;
/*      */   }
/*      */   
/*      */   Metadata encodeMetadata() {
/* 3379 */     Metadata meta = encodeMetadata(new Metadata());
/* 3380 */     if (trackUserAgentInMetadata()) {
/* 3381 */       OperationContext octxt = getMailbox().getOperationContext();
/* 3382 */       if (octxt != null) {
/* 3383 */         meta.put("ua", octxt.getUserAgent());
/*      */       }
/*      */     }
/* 3386 */     return meta;
/*      */   }
/*      */   
/*      */   abstract Metadata encodeMetadata(Metadata paramMetadata);
/*      */   
/*      */   static Metadata encodeMetadata(Metadata meta, Color color, ACL rights, int metaVersion, int version, MailItem.CustomMetadata.CustomMetadataList extended) {
/* 3392 */     if ((color != null) && (color.getMappedColor() != 0)) {
/* 3393 */       meta.put("c", color.toMetadata());
/*      */     }
/* 3395 */     if (metaVersion > 1) {
/* 3396 */       meta.put("mdver", metaVersion);
/*      */     }
/* 3398 */     if (version > 1) {
/* 3399 */       meta.put("ver", version);
/*      */     }
/* 3401 */     if (extended != null) {
/* 3402 */       for (Pair<String, String> mpair : extended) {
/* 3403 */         meta.put("xd." + (String)mpair.getFirst(), mpair.getSecond());
/*      */       }
/*      */     }
/* 3406 */     if (rights != null) {
/* 3407 */       meta.put("aclm", rights.encode());
/*      */     }
/* 3409 */     return meta;
/*      */   }
/*      */   
/*      */   void decodeMetadata(String metadata) throws ServiceException {
/*      */     try {
/* 3414 */       decodeMetadata(new Metadata(metadata, Integer.valueOf(this.mId)));
/*      */     } catch (ServiceException e) {
/* 3416 */       ZimbraLog.mailbox.error("Failed to parse metadata id=%d,type=%s", Integer.valueOf(this.mId), getType(), e);
/* 3417 */       throw e;
/*      */     }
/*      */   }
/*      */   
/*      */   void decodeMetadata(Metadata meta) throws ServiceException {
/* 3422 */     if (meta == null) {
/* 3423 */       return;
/*      */     }
/* 3425 */     this.mRGBColor = Color.fromMetadata(meta.getLong("c", 0L));
/* 3426 */     this.mMetaVersion = ((int)meta.getLong("mdver", 1L));
/* 3427 */     this.mVersion = ((int)meta.getLong("ver", 1L));
/*      */     
/* 3429 */     this.mExtendedData = null;
/* 3430 */     for (Map.Entry<String, ?> entry : meta.asMap().entrySet()) {
/* 3431 */       String key = (String)entry.getKey();
/* 3432 */       if (key.startsWith("xd.")) {
/* 3433 */         if (this.mExtendedData == null) {
/* 3434 */           this.mExtendedData = new MailItem.CustomMetadata.CustomMetadataList();
/*      */         }
/* 3436 */         this.mExtendedData.addSection(key.substring("xd.".length()), entry.getValue().toString());
/*      */       }
/*      */     }
/*      */     
/* 3440 */     ACL acl = null;
/* 3441 */     if (meta.containsKey("aclm"))
/*      */     {
/* 3443 */       acl = makeACLFromMap("aclm", meta);
/* 3444 */     } else if (meta.containsKey("acl")) {
/*      */       try
/*      */       {
/* 3447 */         MetadataList mlistACL = meta.getList("acl", true);
/* 3448 */         if (mlistACL != null) {
/* 3449 */           acl = new ACL(mlistACL);
/*      */         }
/*      */       }
/*      */       catch (ServiceException se) {
/* 3453 */         ZimbraLog.mailbox.warn("Metadata.FN_RIGHTS exists, but is not list. Should never see this outside CF/DF!");
/* 3454 */         acl = makeACLFromMap("acl", meta);
/*      */       }
/*      */     }
/* 3457 */     if (acl != null) {
/* 3458 */       this.rights = (acl.isEmpty() ? null : acl);
/* 3459 */       if (!isTagged(Flag.FlagInfo.NO_INHERIT)) {
/* 3460 */         alterTag(this.mMailbox.getFlagById(Flag.ID_NO_INHERIT), true);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   private ACL makeACLFromMap(String key, Metadata meta) throws ServiceException {
/* 3466 */     Metadata aclMetaData = meta.getMap(key, true);
/* 3467 */     if (aclMetaData != null) {
/* 3468 */       return new ACL(aclMetaData);
/*      */     }
/* 3470 */     return null;
/*      */   }
/*      */   
/*      */   protected void saveMetadata()
/*      */     throws ServiceException
/*      */   {
/* 3476 */     saveMetadata(encodeMetadata().toString());
/*      */   }
/*      */   
/*      */   protected void saveMetadata(String metadata) throws ServiceException {
/* 3480 */     metadataChanged();
/* 3481 */     if (ZimbraLog.mailop.isDebugEnabled()) {
/* 3482 */       ZimbraLog.mailop.debug("saving metadata for " + getMailopContext(this));
/*      */     }
/* 3484 */     DbMailItem.saveMetadata(this, metadata);
/*      */   }
/*      */   
/*      */   protected void saveName() throws ServiceException {
/* 3488 */     saveName(getFolderId());
/*      */   }
/*      */   
/*      */   protected void saveName(int folderId) throws ServiceException {
/* 3492 */     DbMailItem.saveName(this, folderId, encodeMetadata());
/*      */   }
/*      */   
/*      */   protected void saveData(DbMailItem data) throws ServiceException {
/* 3496 */     saveData(data, encodeMetadata());
/*      */   }
/*      */   
/*      */   protected void saveData(DbMailItem data, Metadata metadata) throws ServiceException {
/* 3500 */     assert (metadata != null);
/* 3501 */     metadataChanged();
/* 3502 */     if (ZimbraLog.mailop.isDebugEnabled()) {
/* 3503 */       ZimbraLog.mailop.debug("saving data for %s", new Object[] { getMailopContext(this) });
/*      */     }
/* 3505 */     data.update(this, metadata);
/*      */   }
/*      */   
/*      */   void markMetadataChanged() throws ServiceException {
/* 3509 */     saveData(new DbMailItem(this.mMailbox));
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void lock(Account authuser)
/*      */     throws ServiceException
/*      */   {
/* 3521 */     throw MailServiceException.CANNOT_LOCK(this.mId);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void unlock(Account authuser)
/*      */     throws ServiceException
/*      */   {
/* 3533 */     throw MailServiceException.CANNOT_UNLOCK(this.mId);
/*      */   }
/*      */   
/*      */   List<Comment> getComments(SortBy sortBy, int offset, int length) throws ServiceException {
/* 3537 */     List<UnderlyingData> listData = DbMailItem.getByParent(this, sortBy, -1, inDumpster());
/* 3538 */     ArrayList<Comment> comments = new ArrayList();
/* 3539 */     for (UnderlyingData data : listData) {
/* 3540 */       MailItem item = this.mMailbox.getItem(data);
/* 3541 */       if ((item instanceof Comment)) {
/* 3542 */         comments.add((Comment)item);
/*      */       }
/*      */     }
/* 3545 */     if (comments.size() <= offset) {
/* 3546 */       return Collections.emptyList();
/*      */     }
/* 3548 */     int last = length == -1 ? comments.size() : Math.min(comments.size(), offset + length);
/* 3549 */     return comments.subList(offset, last);
/*      */   }
/*      */   
/*      */   public Metadata serializeUnderlyingData() {
/* 3553 */     Metadata meta = this.mData.serialize();
/*      */     
/* 3555 */     Metadata metaMeta = new Metadata();
/* 3556 */     encodeMetadata(metaMeta);
/* 3557 */     meta.put("meta", metaMeta.toString());
/* 3558 */     return meta;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected Objects.ToStringHelper appendCommonMembers(Objects.ToStringHelper helper)
/*      */   {
/* 3580 */     helper.add("id", this.mId);
/* 3581 */     helper.add("type", this.mData.type);
/* 3582 */     if (this.mData.name != null) {
/* 3583 */       helper.add("name", this.mData.name);
/*      */     }
/* 3585 */     helper.add("unread", this.mData.unreadCount);
/* 3586 */     if (this.mData.getFlags() != 0) {
/* 3587 */       helper.add("flags", getFlagString());
/*      */     }
/* 3589 */     if (this.mData.getTags().length != 0) {
/* 3590 */       helper.add("tags", Joiner.on(',').join(this.mData.getTags()));
/*      */     }
/* 3592 */     helper.add("folder_id", this.mData.folderId);
/* 3593 */     helper.add("size", this.mData.size);
/* 3594 */     helper.add("meta_version", this.mMetaVersion);
/* 3595 */     helper.add("version", this.mVersion);
/* 3596 */     if (this.mData.parentId > 0) {
/* 3597 */       helper.add("parent_id", this.mData.parentId);
/*      */     }
/* 3599 */     if (this.mRGBColor != null) {
/* 3600 */       helper.add("color", this.mRGBColor.getMappedColor());
/*      */     }
/* 3602 */     if (this.mData.getSubject() != null) {
/* 3603 */       helper.add("subject", this.mData.getSubject());
/*      */     }
/* 3605 */     if (getDigest() != null) {
/* 3606 */       helper.add("digest", getDigest());
/*      */     }
/* 3608 */     if (this.mData.imapId > 0) {
/* 3609 */       helper.add("imap_id", this.mData.imapId);
/*      */     }
/* 3611 */     helper.add("date", this.mData.date);
/* 3612 */     helper.add("rev", this.mData.modContent);
/* 3613 */     return helper;
/*      */   }
/*      */   
/*      */   public static Set<Integer> toId(Set<? extends MailItem> items) {
/* 3617 */     if (items == null) {
/* 3618 */       return null;
/*      */     }
/* 3620 */     Set<Integer> result = new HashSet(items.size());
/* 3621 */     for (MailItem item : items) {
/* 3622 */       result.add(Integer.valueOf(item.getId()));
/*      */     }
/* 3624 */     return result;
/*      */   }
/*      */   
/*      */   public static List<Integer> toId(List<? extends MailItem> items) {
/* 3628 */     if (items == null) {
/* 3629 */       return null;
/*      */     }
/* 3631 */     List<Integer> result = new ArrayList(items.size());
/* 3632 */     for (MailItem item : items) {
/* 3633 */       result.add(Integer.valueOf(item.getId()));
/*      */     }
/* 3635 */     return result;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailItem snapshotItem()
/*      */     throws ServiceException
/*      */   {
/* 3646 */     UnderlyingData data = getUnderlyingData().clone();
/* 3647 */     data.setFlag(Flag.FlagInfo.UNCACHED);
/* 3648 */     return constructItem(this.mMailbox, data);
/*      */   }
/*      */   
/*      */   protected short checkACL(short rightsNeeded, Account authuser, boolean asAdmin) throws ServiceException
/*      */   {
/* 3653 */     Short granted = this.rights != null ? this.rights.getGrantedRights(authuser) : null;
/*      */     
/* 3655 */     if (granted != null) {
/* 3656 */       short subset = (short)(granted.shortValue() & rightsNeeded);
/* 3657 */       if (ZimbraLog.acl.isTraceEnabled()) {
/* 3658 */         ZimbraLog.acl.trace("checkACL '%s' returned=%s granted=%s needed=%s (R)", new Object[] { getPath(), Short.valueOf(subset), granted, Short.valueOf(rightsNeeded) });
/*      */       }
/*      */       
/* 3661 */       return (short)(granted.shortValue() & rightsNeeded);
/*      */     }
/*      */     
/* 3664 */     if (this.mId == 11) {
/* 3665 */       if (ZimbraLog.acl.isTraceEnabled()) {
/* 3666 */         ZimbraLog.acl.trace("checkACL '%s' returned=0 granted=0 needed=%s (ROOT)", new Object[] { getPath(), Short.valueOf(rightsNeeded) });
/*      */       }
/* 3668 */       return 0;
/*      */     }
/* 3670 */     if (isTagged(Flag.FlagInfo.NO_INHERIT)) {
/* 3671 */       if (ZimbraLog.acl.isTraceEnabled()) {
/* 3672 */         ZimbraLog.acl.trace("checkACL '%s' returned=0 granted=0 needed=%s (no inherit)", new Object[] { getPath(), Short.valueOf(rightsNeeded) });
/*      */       }
/*      */       
/* 3675 */       return 0;
/*      */     }
/* 3677 */     granted = Short.valueOf(getParent().checkACL(rightsNeeded, authuser, asAdmin));
/* 3678 */     short subset = (short)(granted.shortValue() & rightsNeeded);
/* 3679 */     if (ZimbraLog.acl.isTraceEnabled()) {
/* 3680 */       ZimbraLog.acl.trace("checkACL '%s' returned=%s granted=%s needed=%s (P)", new Object[] { getPath(), Short.valueOf(subset), granted, Short.valueOf(rightsNeeded) });
/*      */     }
/*      */     
/* 3683 */     return granted.shortValue();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   ACL.Grant grantAccess(String zimbraId, byte type, short rights, String args, long expiry)
/*      */     throws ServiceException
/*      */   {
/* 3700 */     Account account = getAccount();
/* 3701 */     if ((type == 6) && (!account.isPublicSharingEnabled())) {
/* 3702 */       throw ServiceException.PERM_DENIED("public sharing not allowed");
/*      */     }
/* 3704 */     if ((type == 7) && ((!account.isExternalSharingEnabled()) || (!isAllowedExternalDomain(zimbraId))))
/*      */     {
/* 3706 */       throw ServiceException.PERM_DENIED("external sharing not allowed");
/*      */     }
/* 3708 */     if (!canAccess((short)256)) {
/* 3709 */       throw ServiceException.PERM_DENIED("you do not have admin rights to item " + getPath());
/*      */     }
/* 3711 */     if ((type == 1) && (zimbraId.equalsIgnoreCase(getMailbox().getAccountId()))) {
/* 3712 */       throw ServiceException.PERM_DENIED("cannot grant access to the owner of the item");
/*      */     }
/*      */     
/* 3715 */     alterTag(this.mMailbox.getFlagById(Flag.ID_NO_INHERIT), true);
/*      */     
/* 3717 */     markItemModified(2097152);
/* 3718 */     if (this.rights == null) {
/* 3719 */       long intShareLifetime = getMaxAllowedInternalShareLifetime(account);
/* 3720 */       long extShareLifetime = getMaxAllowedExternalShareLifetime(account);
/* 3721 */       long now = System.currentTimeMillis();
/* 3722 */       this.rights = new ACL(intShareLifetime == 0L ? 0L : now + intShareLifetime, extShareLifetime == 0L ? 0L : now + extShareLifetime);
/*      */     }
/*      */     
/* 3725 */     ACL.Grant grant = this.rights.grantAccess(zimbraId, type, rights, args, expiry);
/* 3726 */     saveMetadata();
/*      */     
/* 3728 */     queueForAclPush();
/*      */     
/* 3730 */     return grant;
/*      */   }
/*      */   
/*      */   protected long getMaxAllowedExternalShareLifetime(Account account)
/*      */   {
/* 3735 */     return account.getExternalShareLifetime();
/*      */   }
/*      */   
/*      */   protected long getMaxAllowedInternalShareLifetime(Account account)
/*      */   {
/* 3740 */     return account.getShareLifetime();
/*      */   }
/*      */   
/*      */   protected void queueForAclPush() throws ServiceException {
/* 3744 */     DbPendingAclPush.queue(this.mMailbox, this.mId);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void revokeAccess(String zimbraId)
/*      */     throws ServiceException
/*      */   {
/* 3757 */     if (!canAccess((short)256)) {
/* 3758 */       throw ServiceException.PERM_DENIED("you do not have admin rights to item " + getPath());
/*      */     }
/* 3760 */     if (zimbraId.equalsIgnoreCase(getMailbox().getAccountId())) {
/* 3761 */       throw ServiceException.PERM_DENIED("cannot revoke access from the owner of the item");
/*      */     }
/* 3763 */     ACL acl = getEffectiveACL();
/* 3764 */     if ((acl == null) || (!acl.revokeAccess(zimbraId))) {
/* 3765 */       return;
/*      */     }
/*      */     
/* 3768 */     alterTag(this.mMailbox.getFlagById(Flag.ID_NO_INHERIT), true);
/*      */     
/* 3770 */     markItemModified(2097152);
/* 3771 */     this.rights.revokeAccess(zimbraId);
/* 3772 */     if (this.rights.isEmpty()) {
/* 3773 */       this.rights = null;
/*      */     }
/* 3775 */     saveMetadata();
/*      */     
/* 3777 */     queueForAclPush();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void setPermissions(ACL acl)
/*      */     throws ServiceException
/*      */   {
/* 3789 */     if (!canAccess((short)256)) {
/* 3790 */       throw ServiceException.PERM_DENIED("you do not have admin rights to item " + getPath());
/*      */     }
/*      */     
/* 3793 */     alterTag(this.mMailbox.getFlagById(Flag.ID_NO_INHERIT), true);
/*      */     
/* 3795 */     markItemModified(2097152);
/* 3796 */     if ((acl != null) && (acl.isEmpty())) {
/* 3797 */       acl = null;
/*      */     }
/* 3799 */     if ((acl == null) && (this.rights == null)) {
/* 3800 */       return;
/*      */     }
/* 3802 */     this.rights = acl;
/* 3803 */     saveMetadata();
/*      */     
/* 3805 */     queueForAclPush();
/*      */   }
/*      */   
/*      */ 
/*      */   public ACL getACL()
/*      */   {
/* 3811 */     return this.rights == null ? null : this.rights.duplicate();
/*      */   }
/*      */   
/*      */ 
/*      */   public ACL getEffectiveACL()
/*      */   {
/* 3817 */     MailItem parent = null;
/*      */     try {
/* 3819 */       parent = getParent();
/*      */     } catch (ServiceException e) {}
/* 3821 */     if ((this.mId == 11) || (isTagged(Flag.FlagInfo.NO_INHERIT)) || (parent == null)) {
/* 3822 */       return getACL();
/*      */     }
/* 3824 */     return parent.getEffectiveACL();
/*      */   }
/*      */   
/*      */   void metadataChanged(boolean updateFolderMODSEQ) throws ServiceException {
/* 3828 */     this.mMetaVersion += 1;
/* 3829 */     this.mData.metadataChanged(this.mMailbox, updateFolderMODSEQ);
/* 3830 */     if (Zimbra.isAlwaysOn()) {
/* 3831 */       this.mMailbox.cache(this);
/*      */     }
/*      */   }
/*      */   
/*      */   void metadataChanged() throws ServiceException {
/* 3836 */     metadataChanged(true);
/*      */   }
/*      */   
/*      */   void contentChanged() throws ServiceException {
/* 3840 */     this.mMetaVersion += 1;
/* 3841 */     this.mData.contentChanged(this.mMailbox);
/* 3842 */     if (Zimbra.isAlwaysOn()) {
/* 3843 */       this.mMailbox.cache(this);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   public Folder getShare()
/*      */     throws ServiceException
/*      */   {
/* 3851 */     Folder f = getFolder();
/* 3852 */     while (f != null) {
/* 3853 */       if (f.isShare())
/* 3854 */         return f;
/* 3855 */       if (f.getId() == 11) {
/* 3856 */         return null;
/*      */       }
/* 3858 */       f = f.getFolder();
/*      */     }
/* 3860 */     return null;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean isUnder(int folderId)
/*      */     throws ServiceException
/*      */   {
/* 3869 */     Folder f = getFolder();
/* 3870 */     while (f != null) {
/* 3871 */       int fid = f.getId();
/* 3872 */       if (fid == folderId)
/* 3873 */         return true;
/* 3874 */       if (fid == 11) {
/* 3875 */         return false;
/*      */       }
/* 3877 */       f = f.getFolder();
/*      */     }
/* 3879 */     return false;
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailbox/MailItem.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */